使用LocalStorage和DB进行状态无限循环

问题描述

我正在开发一个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,因此每个渲染都会触发另一个渲染,从而使其循环。