首页 > 解决方案 > useEffect 和 watch 状态

问题描述

我正在尝试使用函数调用在渲染时设置项目的状态,然后观察项目状态的变化以在它们发生变化时导致重新渲染。根据建议的答案传递对对象键的引用似乎没有任何改变。我正在尝试使用钩子 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));
    }
}

标签: javascriptreactjsreact-hooks

解决方案


正如评论中所建议的,解决方案是将setItems调用移出useEffect并在其他地方调用它以及updateItem保存/更新数据的函数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渲染后立即获取初始状态,然后该组件的本地状态将在handleQuantityChange处理程序中更新。


推荐阅读