【问题标题】:React Components "flickers" on load, since state gets overridenReact 组件在加载时“闪烁”,因为状态被覆盖
【发布时间】:2021-09-17 17:51:01
【问题描述】:

我使用 React 开发一个待办事项应用程序,事情变得更加清晰,但我很难理解“生命周期”。在 VueJS 中,我知道一个 ComponentDidMount() 钩子,如果我猜它会帮助我解决这个问题,但在 React 中我找不到它。

我有一系列类似的待办事项:const todos = [{description: "walk dog", done: false}]

这是我的应用程序的初始状态:

const [alltodos, handleTodos] = useState([]);

在加载时,我使用这个 useEffect 挂钩从 localStorage 获取数据。

  useEffect(() => {
    const items = localStorage.getItem("todos");
    const parsed = JSON.parse(items);
    handleTodos(parsed);
  }, []);

我用这个函数计算我的待办事项:

  const countTodos = () => {
    const donetodos = alltodos.filter((item) => {
      return !item.done;
    });

    countOpen(donetodos.length);
  };

如果依赖项发生变化,我会更新计数:

  useEffect(() => {
    countTodos();
    localStorage.setItem("todos", JSON.stringify(alltodos));
  }, [alltodos]);

所以发生的情况是计数器从 0 开始,然后“闪烁”一毫秒,然后显示我从 localstorage 获得的待办事项数量。

有没有办法防止这种行为?据我所知,组件首先呈现,然后触发 useEffect 挂钩。从本地存储中提取数据后如何渲染组件?

【问题讨论】:

    标签: javascript reactjs react-hooks use-state


    【解决方案1】:

    最好的方法是使用lazy initial state。此外,清理变量并使用标准化的 [variable, setVariable] 将使您在以后的调试中省去头疼的问题。

    const [alltodos, setAlltodos] = useState(() => {
        const items = localStorage.getItem("todos");
        const parsed = JSON.parse(items);
        return parsed || "";
    });
    

    【讨论】:

    • 谢谢,虽然其他解决方案也可以,但这更容易,我猜是处理它的最佳方法:-)
    【解决方案2】:

    使用null 初始化allTodos 状态。只要这个状态是null,就渲染一个通知或者只返回null 不渲染任何东西。

    您可以直接从当前alltodos 状态计算打开的待办事项计数,而不需要useEffect

    const [alltodos, handleTodos] = useState(null);
    
    useEffect(() => {
      const items = localStorage.getItem("todos");
      const parsed = items ? JSON.parse(items) : [];
      handleTodos(parsed);
    }, []);
    
    useEffect(() => {
      localStorage.setItem("todos", JSON.stringify(alltodos));
    }, [alltodos]);
    
    if(alltodos === null) return 'Loading todos list';
    
    // this is derived from state, so you don't have to create a state for it
    const openTodosCount = alltodos.reduce((acc, o) => acc + !o.done, 0);
    

    【讨论】:

    • 谢谢,非常好的解决方案
    【解决方案3】:

    最快的方法是添加负责加载的新状态。 例如

    const [isLoading, setIsLoading] = useState(true);
    

    最初将其设置为 true,然后在完成所有计算后将其更改为 false

    然后您可以依赖该状态并使用文本 "Loading" 或其他任何内容显示 div,但当 isLoading 转到 false 时,它将显示组件元素。

    【讨论】:

    • 我试过了,但它并没有真正起作用。在哪里放置 useState 函数。我试图把它放在handleTodos(parsed) (setIsLoading(false);) 的下面,但它的行为仍然相同。
    猜你喜欢
    • 2019-07-28
    • 2018-10-05
    • 2021-02-02
    • 2019-03-27
    • 1970-01-01
    • 2021-01-19
    • 2020-09-19
    • 2019-11-29
    • 1970-01-01
    相关资源
    最近更新 更多