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;
添加回答
举报