useEffect和观看状态

时间:2019-08-18 19:24:15

标签: javascript reactjs react-hooks

我正在尝试使用函数调用设置渲染状态下的项目状态,然后观察项目状态是否发生更改,如果更改则导致重新渲染。建议的答案似乎没有任何改变。我正在尝试使用挂钩useEffect()。 getCart()是从localStorage检索数据的功能。代码:

const [items, setItems] = useState([]);

useEffect(() => {
    setItems(getCart());
}, [items]);

我收到错误消息“超出最大更新深度。当组件在useEffect内调用setState时会发生这种情况,但useEffect要么没有依赖项数组,要么每个渲染项的依赖项都发生变化。”

我了解如何通过有效地更改渲染中的项目状态导致无限循环,然后导致重新渲染,等等。我如何解决这个问题,可以使用useEffect吗?谢谢。

编辑:用于编辑localStorage的代码

export const updateItem = (productId, count) => {
   let cart = [];
   if (typeof window !== 'undefined') {
        if (localStorage.getItem('cart')) {
            cart = JSON.parse(localStorage.getItem('cart'));
        }
        cart.map((product, index) => {
            if (product._id === productId) {
                cart[index].count = count;
            }
        })
        localStorage.setItem('cart', JSON.stringify(cart));
    }
}

3 个答案:

答案 0 :(得分:2)

如评论中所建议,解决方案是将setItems调用移出useEffect并与updateItem函数一起在其他地方进行调用,该函数将数据保存/更新到{{ 1}}:

localStorage

这样,调用// cart.js export const updateItem = (productId, count) => { // see implementation above } // App.js function App() { const [items, setItems] = useState([]) useEffect(() => { const cartItems = getCart() setItems(cartItems) // pass an empty dependency array so that this hook // runs only once and gets data from `localStorage` when it first mounts }, []) const handleQuantityChange = (data) => { // this will update `localStorage`, get new cart state // from `localStorage`, and update state inside of this component updateItem(data.productId, data.count) const currentCart = getCart() setItems(currentCart) } return ( <div> {...} <button onClick={() => handleQuantityChange(...)> Add more </button> </div> ) } 很好,因为只有在单击按钮时才会触发它。

此外,由于setItems带有一个空的依赖项数组,它将不再导致useEffect错误,因为它将仅运行一次以从maxiumum update depth exceeded获得初始状态渲染,则该组件的本地状态将在localStorage处理程序中更新。

答案 1 :(得分:0)

从依赖项数组中删除“项”。这样,它将仅从第一个渲染器上的本地存储中获取项目(这就是您想要的)。项目的其他任何更新都应由用户完成,而不是每次重新渲染都会自动触发。

const [items, setItems] = useState([]);

useEffect(() => {
    setItems(getCart());
}, []);

答案 2 :(得分:0)

如果要在useState中使用数组,则需要确保每次值更改时该数组都有不同的引用。

您可以在控制台中尝试以下操作:

a = [1, 2, 3] // a = [1, 2, 3]
b = a         // b = [1, 2, 3]
a.push(4)     // a = b = [1, 2, 3, 4]
b === a       // true

通知b仍然等于a,即使a中的值发生了变化。发生的事情是React.useState,而React.useEffect使用简单的===将旧状态与新状态进行比较。为了确保每次都能看到不同的数组,请使用rest运算符将a的所有内容复制到b中,如下所示:

a = [1, 2, 3] // a = [1, 2, 3]
b = [...a]    // b = [1, 2, 3]
a.push(4)     // a = [1, 2, 3, 4], b = [1, 2, 3]
b === a       // false

如果执行此操作,则仅在数据确实不同时才会调用useEffect

您还应注意的另一件事是,请勿setItems内调用useEffect内的[items]。您应该将getCart()的结果放在另一个状态变量中。