为啥 useEffect 钩子在第一次渲染时不调用函数?

Posted

技术标签:

【中文标题】为啥 useEffect 钩子在第一次渲染时不调用函数?【英文标题】:Why is useEffect hook not calling functions in first render?为什么 useEffect 钩子在第一次渲染时不调用函数? 【发布时间】:2021-11-22 14:14:04 【问题描述】:

readTodos() 是一个 redux 动作创建者,它从 localstorage 获取 Todo 项并将它们存储在 redux 状态 (globalstate)。我想在useEffect 函数中调用readTodos() 函数并更新globalstate 变量,该变量将在第一次渲染中显示ViewTodos 组件中的所有TodoItems。但是,当组件加载并且返回函数中的列表没有被填充时,readTodos() 操作不会被调用。

import Container from 'react-bootstrap/Container';
import   useEffect, useState  from "react";
import  useDispatch,useSelector  from "react-redux";
import  bindActionCreators  from "redux";
import  actionCreators,State  from "../../state/state";
import  TodoInterface  from "./interfaces";
import   Row  from 'react-bootstrap';
import "../styles/createTodoStyles.css"

export const ViewTodos =():JSX.Element =>
   //REDUX starts here
  const dispatch = useDispatch();
  const readTodos =bindActionCreators(actionCreators,dispatch);
  const globalstate = useSelector((state:State) => state.todo)

   useEffect(()=>
    readTodos();
   ,[]);
    
    return(
        <Container>
          <Row>
              <h1>Todo List</h1><ul>
        
          globalstate.Inprogress.map(Element =>
            return (
              <li> Element.Title </li>
            )
          )
        
        </ul>
          </Row>
          
        </Container>
    )

readTodos()动作创建者代码:

export const readTodos = () =>

    var mystorage = window.localStorage;
    var Completed = JSON.parse(mystorage.getItem("completed")|| "[]");
    var Inprogress = JSON.parse(mystorage.getItem("inprogress")|| "[]");

    var todolist=
        Completed:Completed,
        Inprogress:Inprogress
    

    return (dispatch:Dispatch) =>
        dispatch(
            type:"readTodo",
            payload:todolist
        )
    

【问题讨论】:

您是否通过在函数中放置console.log() 来验证readTodos() 实际上没有被调用?在 react 生命周期中,useEffect 在组件挂载后被调用。 我刚刚尝试过,它在第一次渲染时被调用。我的 redux 状态变量(globalstate)也在更新,但是我的 Todos 列表没有更新。 【参考方案1】:

您的 redux 操作是异步的,因此即使它在初始渲染时启动,该数据在渲染结束时还没有加载到 redux 存储中。我建议在尝试映射之前检查以确保 globalState.Inprogress 存在(或长度大于零,具体取决于您的用例)。

return (
  <Container>
    <Row>
      <h1>Todo List</h1>
      <ul>
        globalstate.Inprogress && // or globalstate.Inprogress.length > 0 &&
          globalstate.Inprogress.map(Element =>
            return (
              <li> Element.Title </li>
            )
          )
        
      </ul>
    </Row>
  </Container>
)

【讨论】:

本地存储上的操作本质上是异步的还是 redux 调度本身是异步的?我已经更新了描述中的代码。我尝试检查 globalState.Inprogress 是否存在,但它对我不起作用。

以上是关于为啥 useEffect 钩子在第一次渲染时不调用函数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在组件加载时不调用 useEffect(()=...,[]) ?

渲染组件时不触发 useEffect

为啥每次渲染都会调用 `useEffect` 的清理功能?

在使用 graphql 的 useQuery 获取的数据更新 useEffect 钩子内的状态变量时防止无限渲染

如何避免在每次渲染时触发useEffect?

useEffect 钩子完成后如何渲染组件?