4 回答

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演示中刪除了它,所以你可以看到差異

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({});

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>
));
}
這是更新的演示

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;
添加回答
舉報