使用效果和监视状态



我正在尝试使用函数调用在渲染时设置项目的状态,然后观察项目状态的更改,以便在它们发生变化时导致重新渲染。根据建议的答案传递对对象键的引用似乎不会改变任何内容。我正在尝试使用钩子useEffect((来做到这一点。getCart(( 是一个从 localStorage 检索数据的函数。法典:

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

我收到错误"超出最大更新深度。当组件在 useEffect 中调用 setState 时,可能会发生这种情况,但 useEffect 要么没有依赖项数组,要么每个渲染时都有一个依赖项更改。

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

编辑:编辑本地存储的代码

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));
}
}

如注释中所建议的,解决方案是将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处理程序中更新。

如果你想在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.useStateReact.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()的结果放在另一个状态变量中。

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

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

相关内容

  • 没有找到相关文章

最新更新