React:使用 useEffect 和/或 useState 钩子混淆行为

在这里反应菜鸟。我正在尝试制作一个简单的练习应用程序来帮助我学习 React,但我遇到了很多奇怪的行为。这是一个有多个待办事项列表可供选择的待办事项应用程序。我要的行为是一个待办事项列表的列表,您可以在其中选择一个和待办事项(如 wunderlist/msft 待办事项)。选择一个不同的列表,它的待办事项显示等。此时它使用静态 json,其中每个项目都有一个子数组。


useEffect - 我正在尝试使用它来加载数据。它一直抱怨缺少依赖项。当我添加它们时,它也会抱怨这一点。如果我对第二个参数使用空数组并且似乎多次触发,它会抱怨。


useState - 我用它来存储数据。它被初始化为一个空数组。但是 render 在 useEffect 之前触发,它说我的数据是未定义的,所以我的第二个列表永远不会呈现。


我在代码中有几个console.logs,它们都被多次触发。


我敢肯定这只是菜鸟的错误,但在这一点上我很困惑。这是我的代码:


数据/Todo.js


const TodoData = [

  {

    Id: 1,

    Title: "Groceries",

    TodoList: [

      {

        Id: 1,

        Title: "Apples"

      },

      {

        Id: 2,

        Title: "Oranges"

      },

      {

        Id: 3,

        Title: "Bananas"

      }

    ]

  },

  {

    Id: 2,

    Title: "Daily Tasks",

    TodoList: [

      {

        Id: 11,

        Title: "Clean Kitchen"

      },

      {

        Id: 12,

        Title: "Feed Pets"

      },

      {

        Id: 13,

        Title: "Do Stuff"

      }

    ]

  },

  {

    Id: 3,

    Title: "Hardware Store",

    TodoList: []

  },

  {

    Id: 4,

    Title: "Costco",

    TodoList: [

      {

        Id: 21,

        Title: "Diapers"

      },

      {

        Id: 22,

        Title: "Cat Food"

      },

      {

        Id: 23,

        Title: "Apples"

      },

      {

        Id: 24,

        Title: "Bananas"

      }

    ]

  },

  {

    Id: 5,

    Title: "Work",

    TodoList: [

      {

        Id: 34,

        Title: "TPS Reports"

      }

    ]

  }

];


export default TodoData;


繁星点点滴滴
浏览 107回答 4
4回答

梦里花落0921

问: useEffect - 我正在尝试使用它来加载数据。它一直抱怨缺少依赖项答:你可以忽略它eslint (react-hooks/exhaustive-deps),不用担心问: useState - 我用它来存储数据。它被初始化为一个空数组。但是 render 在 useEffect 之前触发,它说我的数据是未定义的,所以我的第二个列表永远不会呈现。A :请阅读代码中的注释,希望能消除您的疑虑// you are intializing `todoDetails` with array, when there will be object// hence the error while mapping inside the html/jsx// const [todoDetails, setTodoDetails] = useState([]);// init with `null`, why?const [todoDetails, setTodoDetails] = useState(null);// so that you can do something like this{&nbsp; todoDetails && (&nbsp; &nbsp;// <---------- HERE&nbsp; &nbsp; <ul className="list-group">&nbsp; &nbsp; &nbsp; <h2>{todoDetails.Title} List</h2>&nbsp; &nbsp; &nbsp; {console.log(todoDetails.TodoList)}&nbsp; &nbsp; &nbsp; {/* this fails miserably */}&nbsp; &nbsp; &nbsp; {todoDetails.TodoList.map(details => (&nbsp; &nbsp; &nbsp; &nbsp; <li className="list-group-item" key={details.Id}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {details.Title}&nbsp; &nbsp; &nbsp; &nbsp; </li>&nbsp; &nbsp; &nbsp; ))}&nbsp; &nbsp; </ul>&nbsp; )}问:现在你得到多个console.log,A:这背后的原因是<React.StrictMode>,React 可能在提交之前多次调用渲染阶段生命周期,或者它可能在根本不提交的情况下调用它们(因为错误或更高优先级的中断)。我已经从index.js演示中删除了它,所以你可以看到差异

牛魔王的故事

您评论并说失败的代码是由于todoDetails.TodoList在您第一次渲染组件时未定义。为了避免这种情况,要么todoDetails用一个项目初始化,要么在调用它之前检查是否todoDetails.TodoList已定义.map。{todoDetails.TodoList ? todoDetails.TodoList.map(details => (&nbsp; <li className="list-group-item" key={details.Id}>&nbsp; &nbsp; {details.Title}&nbsp; </li>)) : null}或者const [todoDetails, setTodoDetails] = useState(TodoData[0]);不要太担心eslint (react-hooks/exhaustive-deps)错误。您需要了解这第二个参数的useEffect含义。在您的代码中,您将 传递todoData给useEffect:&nbsp; useEffect(() => {&nbsp; &nbsp; if (todoData.length === 0) {&nbsp; &nbsp; &nbsp; getTodoData();&nbsp; &nbsp; }&nbsp; }, [todoData]);这意味着,无论何时todoData发生更改,useEffect都会运行,表现得像componentDidUpdate. 如果你只传递一个空数组,这意味着你的 useEffect 没有依赖关系,它只会被执行一次,表现得像一个componentDidMount. 所以,你在这里做的很好。除此之外,我可以为您提供一些关于您的代码的提示:关于您的handleClick函数,您可以删除它并简单地调用getTodoDetails(id)传递 id 而不是将其添加到data-id并稍后获取它,这样:<button&nbsp; key={todos.Id}&nbsp; className="btn list-group-item d-flex justify-content-between align-items-center"&nbsp; onClick={() => getTodoDetails(todos.Id)} // <---- change is in here>&nbsp; {todos.Title}&nbsp; <span className="badge badge-primary badge-pill">&nbsp; &nbsp; {todos.TodoList.length}&nbsp; </span></button>在您的 上getTodoDetails,您可以将 更改filter为find,因为您无需遍历整个数组即可找到一项,从而使其更昂贵。另外,这样,您无需访问数组的第一项。const getTodoDetails = id => {&nbsp; const result = TodoData.find(x => x.Id === id);&nbsp; console.log(result);&nbsp; setTodoDetails(result);};您正在使用您的todoDetailsasobject并将其初始化为array. 如果您todoDetails总是只有一个待办事项,请将其初始化为对象,这样您可以防止todoDetails.Title从数组访问。将useEffect始终在渲染后执行。const [todoDetails, setTodoDetails] = useState({});

慕桂英546537

你必须把getTodoData的逻辑放到useEffect钩子里useEffect(() => {&nbsp; &nbsp; const getTodoData = () => {&nbsp; &nbsp; &nbsp; setTodoData(TodoData);&nbsp; &nbsp; &nbsp; console.log("getting todo data");&nbsp; &nbsp; &nbsp; getTodoDetails(1);&nbsp; &nbsp; };&nbsp; &nbsp; if (todoData.length === 0) {&nbsp; &nbsp; &nbsp; getTodoData();&nbsp; &nbsp; }&nbsp; }, [todoData.length]);在渲染中{&nbsp; // check todoDetails has TodoList&nbsp; todoDetails.TodoList &&&nbsp; &nbsp; todoDetails.TodoList.map((details) => (&nbsp; &nbsp; &nbsp; <li className="list-group-item" key={details.Id}>&nbsp; &nbsp; &nbsp; &nbsp; {details.Title}&nbsp; &nbsp; &nbsp; </li>&nbsp; &nbsp; ));}这是更新的演示

千巷猫影

useEffect钩子有时会很奇怪。要修复它,您只需getTodoData像这样直接传递您的函数:&nbsp;const getTodoData = () => {&nbsp; setTodoData(TodoData);&nbsp; console.log("getting todo data");&nbsp; getTodoDetails(1);};useEffect(getTodoData, []);getTodoData在传递函数之前定义函数很重要,useEffect否则会出错。我取消了您“惨遭失败”的代码的注释,并且能够使一切工作完美无缺。这是您的固定App.js文件的全部内容:import React, { useEffect, useState } from "react";import TodoData from "./data/Todo.js";function App() {&nbsp; const [todoData, setTodoData] = useState([]);&nbsp; const [todoDetails, setTodoDetails] = useState([]);&nbsp; const getTodoData = () => {&nbsp; &nbsp; setTodoData(TodoData);&nbsp; &nbsp; console.log("getting todo data");&nbsp; &nbsp; getTodoDetails(1);&nbsp; };&nbsp; useEffect(getTodoData, []);&nbsp; const getTodoDetails = id => {&nbsp; &nbsp; const result = TodoData.filter(x => x.Id === id);&nbsp; &nbsp; console.log(result[0]);&nbsp; &nbsp; setTodoDetails(result[0]);&nbsp; };&nbsp; const handleClick = e => {&nbsp; &nbsp; const selectedId = Number(e.target.getAttribute("data-id"));&nbsp; &nbsp; getTodoDetails(selectedId);&nbsp; };&nbsp; return (&nbsp; &nbsp; <div className="App">&nbsp; &nbsp; &nbsp; <div className="container-fluid">&nbsp; &nbsp; &nbsp; &nbsp; <div className="row">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <div className="list-group col-md-4 offset-md-1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {todoData.map(todos => (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <button&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key={todos.Id}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data-id={todos.Id}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; className="btn list-group-item d-flex justify-content-between align-items-center"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onClick={handleClick}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {todos.Title}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span className="badge badge-primary badge-pill">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {todos.TodoList.length}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </button>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ))}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <div className="col-md-6">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <ul className="list-group">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <h2>{todoDetails.Title} List</h2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {console.log(todoDetails.TodoList)}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {todoDetails.TodoList.map(details => (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <li className="list-group-item" key={details.Id}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {details.Title}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </li>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ))}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </ul>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; &nbsp; &nbsp;</div>&nbsp; &nbsp; </div>&nbsp; &nbsp;);}export default App;
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript