亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

React:使用 useEffect 和/或 useState 鉤子混淆行為

React:使用 useEffect 和/或 useState 鉤子混淆行為

繁星點點滴滴 2022-10-13 16:58:52
在這里反應菜鳥。我正在嘗試制作一個簡單的練習應用程序來幫助我學習 React,但我遇到了很多奇怪的行為。這是一個有多個待辦事項列表可供選擇的待辦事項應用程序。我要的行為是一個待辦事項列表的列表,您可以在其中選擇一個和待辦事項(如 wunderlist/msft 待辦事項)。選擇一個不同的列表,它的待辦事項顯示等。此時它使用靜態 json,其中每個項目都有一個子數組。useEffect - 我正在嘗試使用它來加載數據。它一直抱怨缺少依賴項。當我添加它們時,它也會抱怨這一點。如果我對第二個參數使用空數組并且似乎多次觸發,它會抱怨。useState - 我用它來存儲數據。它被初始化為一個空數組。但是 render 在 useEffect 之前觸發,它說我的數據是未定義的,所以我的第二個列表永遠不會呈現。我在代碼中有幾個console.logs,它們都被多次觸發。我敢肯定這只是菜鳥的錯誤,但在這一點上我很困惑。這是我的代碼:數據/Todo.jsconst 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;
查看完整描述

4 回答

?
夢里花落0921

TA貢獻1772條經驗 獲得超6個贊

問: 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

{

  todoDetails && (   // <---------- HERE

    <ul className="list-group">

      <h2>{todoDetails.Title} List</h2>


      {console.log(todoDetails.TodoList)}


      {/* this fails miserably */}

      {todoDetails.TodoList.map(details => (

        <li className="list-group-item" key={details.Id}>

          {details.Title}

        </li>

      ))}

    </ul>

  )

}

問:現在你得到多個console.log,


A:這背后的原因是<React.StrictMode>,


React 可能在提交之前多次調用渲染階段生命周期,或者它可能在根本不提交的情況下調用它們(因為錯誤或更高優先級的中斷)。


我已經從index.js演示中刪除了它,所以你可以看到差異


查看完整回答
反對 回復 2022-10-13
?
牛魔王的故事

TA貢獻1830條經驗 獲得超3個贊

您評論并說失敗的代碼是由于todoDetails.TodoList在您第一次渲染組件時未定義。為了避免這種情況,要么todoDetails用一個項目初始化,要么在調用它之前檢查是否todoDetails.TodoList已定義.map。


{todoDetails.TodoList ? todoDetails.TodoList.map(details => (

  <li className="list-group-item" key={details.Id}>

    {details.Title}

  </li>

)) : null}

或者


const [todoDetails, setTodoDetails] = useState(TodoData[0]);

不要太擔心eslint (react-hooks/exhaustive-deps)錯誤。您需要了解這第二個參數的useEffect含義。在您的代碼中,您將 傳遞todoData給useEffect:


  useEffect(() => {

    if (todoData.length === 0) {

      getTodoData();

    }

  }, [todoData]);

這意味著,無論何時todoData發生更改,useEffect都會運行,表現得像componentDidUpdate. 如果你只傳遞一個空數組,這意味著你的 useEffect 沒有依賴關系,它只會被執行一次,表現得像一個componentDidMount. 所以,你在這里做的很好。


除此之外,我可以為您提供一些關于您的代碼的提示:


關于您的handleClick函數,您可以刪除它并簡單地調用getTodoDetails(id)傳遞 id 而不是將其添加到data-id并稍后獲取它,這樣:


<button

  key={todos.Id}

  className="btn list-group-item d-flex justify-content-between align-items-center"

  onClick={() => getTodoDetails(todos.Id)} // <---- change is in here

>

  {todos.Title}

  <span className="badge badge-primary badge-pill">

    {todos.TodoList.length}

  </span>

</button>

在您的 上getTodoDetails,您可以將 更改filter為find,因為您無需遍歷整個數組即可找到一項,從而使其更昂貴。另外,這樣,您無需訪問數組的第一項。


const getTodoDetails = id => {

  const result = TodoData.find(x => x.Id === id);

  console.log(result);

  setTodoDetails(result);

};

您正在使用您的todoDetailsasobject并將其初始化為array. 如果您todoDetails總是只有一個待辦事項,請將其初始化為對象,這樣您可以防止todoDetails.Title從數組訪問。將useEffect始終在渲染后執行。


const [todoDetails, setTodoDetails] = useState({});


查看完整回答
反對 回復 2022-10-13
?
慕桂英546537

TA貢獻1848條經驗 獲得超10個贊

你必須把getTodoData的邏輯放到useEffect鉤子里


useEffect(() => {

    const getTodoData = () => {

      setTodoData(TodoData);

      console.log("getting todo data");

      getTodoDetails(1);

    };


    if (todoData.length === 0) {

      getTodoData();

    }

  }, [todoData.length]);

在渲染中


{

  // check todoDetails has TodoList

  todoDetails.TodoList &&

    todoDetails.TodoList.map((details) => (

      <li className="list-group-item" key={details.Id}>

        {details.Title}

      </li>

    ));

}

這是更新的演示


查看完整回答
反對 回復 2022-10-13
?
千巷貓影

TA貢獻1829條經驗 獲得超7個贊

useEffect鉤子有時會很奇怪。要修復它,您只需getTodoData像這樣直接傳遞您的函數:


 const getTodoData = () => {

  setTodoData(TodoData);

  console.log("getting todo data");

  getTodoDetails(1);

};


useEffect(getTodoData, []);

getTodoData在傳遞函數之前定義函數很重要,useEffect否則會出錯。


我取消了您“慘遭失敗”的代碼的注釋,并且能夠使一切工作完美無缺。


這是您的固定App.js文件的全部內容:


import React, { useEffect, useState } from "react";

import TodoData from "./data/Todo.js";


function App() {

  const [todoData, setTodoData] = useState([]);

  const [todoDetails, setTodoDetails] = useState([]);


  const getTodoData = () => {

    setTodoData(TodoData);

    console.log("getting todo data");

    getTodoDetails(1);

  };


  useEffect(getTodoData, []);


  const getTodoDetails = id => {

    const result = TodoData.filter(x => x.Id === id);

    console.log(result[0]);

    setTodoDetails(result[0]);

  };


  const handleClick = e => {

    const selectedId = Number(e.target.getAttribute("data-id"));

    getTodoDetails(selectedId);

  };


  return (

    <div className="App">

      <div className="container-fluid">

        <div className="row">

          <div className="list-group col-md-4 offset-md-1">

            {todoData.map(todos => (

              <button

                key={todos.Id}

                data-id={todos.Id}

                className="btn list-group-item d-flex justify-content-between align-items-center"

                onClick={handleClick}

              >

                {todos.Title}

                <span className="badge badge-primary badge-pill">

                  {todos.TodoList.length}

                </span>

              </button>

            ))}

          </div>

          <div className="col-md-6">

            <ul className="list-group">

              <h2>{todoDetails.Title} List</h2>


              {console.log(todoDetails.TodoList)}


              {todoDetails.TodoList.map(details => (

                <li className="list-group-item" key={details.Id}>

                  {details.Title}

                </li>

              ))}

            </ul>

          </div>

        </div>

       </div>

    </div>

   );

}

export default App;


查看完整回答
反對 回復 2022-10-13
  • 4 回答
  • 0 關注
  • 161 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號