问题描述
我正在开发一个eComm网站,该网站将用户的购物车保持在全局状态以及浏览器的本地存储中。
当他们前往购物车或结帐页面时,我将获取全局状态并将其发送到API进行验证,然后返回购物车的“真实”状态。然后,我想更新全局状态以反映此API数据。
因此,该应用程序将挂载,检查本地存储并由此创建全局状态。在“购物车”和“结帐”页面上,我有一个useEffect,它在监听全局useContext来进行全局状态更改。
由于当前阶段尚未加载本地存储,我无法在挂载上使用
useEffect(()=>{},[])
如何避免这种情况造成的循环?
这是useEffect和依赖项的要点。
TIA!
const globalState = useGlobalState()
const dispatch = usedispatchGlobalState()
useEffect(() => {
if (globalState.cart.length > 0) {
fetch('/api...',{
method: 'POST',headers: {
'Content-Type': 'application/json'
},body: JSON.stringify(globalState.cart)
})
.then((response) => {
return response.json()
})
.then((dbcart) => {
dispatch({
type: 'update global state',payload: {
cart: dbcart
}
})
})
.catch((error) => {
...
})
}
},[globalState])
解决方法
您的globalState是一个对象。通过分派更新该对象时,将更改对该对象的引用。 由于您的对象位于useEffect的依赖项数组中。 useEffect再次运行,导致触发多重重渲染。
请确保在您的useEffect
中使用变量作为依赖项。
此外,您可以使用ref并在分派完成后更新该ref。 下次重新渲染时,您可以检查参考。
function App() {
const globalState = useGlobalState();
const dispatch = useDispatchGlobalState();
const hasUpated = React.useRef(false);
useEffect(() => {
if (globalState.cart.length > 0 && !hasUpdated.current) {
fetch("/api...",{
method: "POST",headers: {
"Content-Type": "application/json"
},body: JSON.stringify(globalState.cart)
})
.then(response => {
return response.json();
})
.then(dbcart => {
hasUpated.current = true;
dispatch({
type: "update global state",payload: {
cart: dbcart
}
});
});
}
},[globalState]);
return null;
}
,
引用React文档:
有条件地发射效果
效果的默认行为是在每次完成后触发效果 渲染。这样,如果依赖关系之一发生更改,则始终会重新创建效果。 但是,在某些情况下(例如上一节中的订阅示例),这可能会显得过于矫kill过正。仅在源支持已更改的情况下,我们不需要在每次更新时都创建新的订阅。
您提供的函数会在每次渲染时更改globalState
,因此每个渲染都会触发另一个渲染,从而使其循环。