4 回答

TA貢獻(xiàn)1772條經(jīng)驗(yàn) 獲得超6個(gè)贊
問: useEffect - 我正在嘗試使用它來加載數(shù)據(jù)。它一直抱怨缺少依賴項(xiàng)
答:你可以忽略它eslint (react-hooks/exhaustive-deps),不用擔(dān)心
問: useState - 我用它來存儲(chǔ)數(shù)據(jù)。它被初始化為一個(gè)空數(shù)組。但是 render 在 useEffect 之前觸發(fā),它說我的數(shù)據(jù)是未定義的,所以我的第二個(gè)列表永遠(yuǎn)不會(huì)呈現(xiàn)。
A :請(qǐng)閱讀代碼中的注釋,希望能消除您的疑慮
// 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>
)
}
問:現(xiàn)在你得到多個(gè)console.log,
A:這背后的原因是<React.StrictMode>
,
React 可能在提交之前多次調(diào)用渲染階段生命周期,或者它可能在根本不提交的情況下調(diào)用它們(因?yàn)殄e(cuò)誤或更高優(yōu)先級(jí)的中斷)。
我已經(jīng)從index.js演示中刪除了它,所以你可以看到差異

TA貢獻(xiàn)1830條經(jīng)驗(yàn) 獲得超3個(gè)贊
您評(píng)論并說失敗的代碼是由于todoDetails.TodoList在您第一次渲染組件時(shí)未定義。為了避免這種情況,要么todoDetails用一個(gè)項(xiàng)目初始化,要么在調(diào)用它之前檢查是否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]);
不要太擔(dān)心eslint (react-hooks/exhaustive-deps)錯(cuò)誤。您需要了解這第二個(gè)參數(shù)的useEffect含義。在您的代碼中,您將 傳遞todoData給useEffect:
useEffect(() => {
if (todoData.length === 0) {
getTodoData();
}
}, [todoData]);
這意味著,無論何時(shí)todoData發(fā)生更改,useEffect都會(huì)運(yùn)行,表現(xiàn)得像componentDidUpdate. 如果你只傳遞一個(gè)空數(shù)組,這意味著你的 useEffect 沒有依賴關(guān)系,它只會(huì)被執(zhí)行一次,表現(xiàn)得像一個(gè)componentDidMount. 所以,你在這里做的很好。
除此之外,我可以為您提供一些關(guān)于您的代碼的提示:
關(guān)于您的handleClick函數(shù),您可以刪除它并簡(jiǎn)單地調(diào)用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,因?yàn)槟鸁o需遍歷整個(gè)數(shù)組即可找到一項(xiàng),從而使其更昂貴。另外,這樣,您無需訪問數(shù)組的第一項(xiàng)。
const getTodoDetails = id => {
const result = TodoData.find(x => x.Id === id);
console.log(result);
setTodoDetails(result);
};
您正在使用您的todoDetailsasobject并將其初始化為array. 如果您todoDetails總是只有一個(gè)待辦事項(xiàng),請(qǐng)將其初始化為對(duì)象,這樣您可以防止todoDetails.Title從數(shù)組訪問。將useEffect始終在渲染后執(zhí)行。
const [todoDetails, setTodoDetails] = useState({});

TA貢獻(xiàn)1848條經(jīng)驗(yàn) 獲得超10個(gè)贊
你必須把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貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超7個(gè)贊
useEffect鉤子有時(shí)會(huì)很奇怪。要修復(fù)它,您只需getTodoData像這樣直接傳遞您的函數(shù):
const getTodoData = () => {
setTodoData(TodoData);
console.log("getting todo data");
getTodoDetails(1);
};
useEffect(getTodoData, []);
getTodoData在傳遞函數(shù)之前定義函數(shù)很重要,useEffect否則會(huì)出錯(cuò)。
我取消了您“慘遭失敗”的代碼的注釋,并且能夠使一切工作完美無缺。
這是您的固定App.js文件的全部?jī)?nèi)容:
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;
添加回答
舉報(bào)