useEffect 不监听 localStorage

IT技术 javascript node.js reactjs react-hooks local-storage
2021-03-30 14:54:56

我正在制作一个身份验证系统,在后端将我重定向到前端页面后,我正在为 userData 发出 API 请求,并将该数据保存到 localStorage。然后我试图加载 Spinner 或 UserInfo。

我正在尝试使用 useEffect 侦听 localStorage 值,但登录后我得到“未定义”。当 localStorage 值更新时 useEffect 不会再次运行并且 Spinner 永远保持旋转。

我试图做:JSON.parse(localStorage.getItem('userData')),但后来我得到了一个 useEffect 无限循环。

只有当我刷新页面时,我的 localStorage 值才会出现,我可以显示它而不是 Spinner。

我做错了什么?

也许有更好的方法在准备好时加载 userData?

我正在尝试以正确的方式更新 DOM?

感谢您的回答;)

import React, { useState, useEffect } from 'react';
import { Spinner } from '../../atoms';
import { Navbar } from '../../organisms/';
import { getUserData } from '../../../helpers/functions';

const Main = () => {
  const [userData, setUserData] = useState();
  useEffect(() => {
    setUserData(localStorage.getItem('userData'));
  }, [localStorage.getItem('userData')]);

  return <>{userData ? <Navbar /> : <Spinner />}</>;
};

export default Main;
4个回答

最好在此处为 localstorage 添加一个事件侦听器。

useEffect(() => {
  function checkUserData() {
    const item = localStorage.getItem('userData')

    if (item) {
      setUserData(item)
    }
  }

  window.addEventListener('storage', checkUserData)

  return () => {
    window.removeEventListener('storage', checkUserData)
  }
}, [])
@Minan 我很难在项目中重现此逻辑,不知道为什么存储上的事件侦听器对 removeItem 事件没有反应,向您的沙箱添加了第二个按钮:codesandbox.io/s/elegant-star-yw1z5
2021-05-25 14:54:56
你好,你能帮我解决这个问题吗?stackoverflow.com/questions/62906923/...
2021-05-30 14:54:56
扩展此答案:OPs 示例不起作用的原因是因为传递给 useEffect 的依赖项数组决定了在呈现组件时是否重新运行效果,这意味着如果 localStorage 效果将重新运行改变了,它必须先渲染。解决这个问题的方法是像 Minan 一样设置对 localStorage 的订阅,以监视更改并通知组件重新渲染。
2021-05-31 14:54:56
什么这个这是否意味着不会在更改存储的选项卡中触发 eventListener?
2021-06-05 14:54:56
实际上,它不是那样工作的。正如您在此示例演示中看到的,所有值继续同步工作。演示 => mq4uu.csb.app代码 => codesandbox.io/s/bold-rain-mq4uu
2021-06-14 14:54:56

“存储”事件的事件侦听器在同一页面中不起作用

当存储区域 (localStorage) 在另一个文档的上下文中被修改时,将触发 Window 接口的存储事件。

https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event

解决方案是使用这种结构:

useEffect(() => {
    window.addEventListener("storage", () => {
      // When storage changes refetch
      refetch();
    });

    return () => {
      // When the component unmounts remove the event listener
      window.removeEventListener("storage");
    };
}, []);
  • “也许有更好的方法在 userData 准备好后加载它?”

您可以将值直接评估到 localStorage 中,而不是传递给状态。

const Main = () => {
  if (localStage.getItem('userData')) {
    return (<Navbar />);
  }
  else {
    return (<Spinner />);
  }
};

如果需要在更多组件中检索userData,评估 Redux 到您的应用程序的实现,这可以消除 localStorage 的使用,但当然,这取决于您的需求。

这会在每次重新渲染时阻塞线程读入 localstorage,所以要小心
2021-05-22 14:54:56
@hakazvaka 使用 IndexedDB 可以解决这个问题吗?知道异步工作......
2021-05-26 14:54:56
通过这种方式,它捕获“未定义”值(并且微调器将永远旋转)。当几秒钟后值“undefined”被更新时,它不会更新DOM。
2021-05-28 14:54:56
有趣...尝试将 userData 作为道具传递给 Main 组件。
2021-06-21 14:54:56