Javascript 反应:将行为与useEffect和/或useState挂钩混淆
这里是诺布。我正在尝试制作一个简单的练习应用程序来帮助我的反应学习,我得到了很多奇怪的行为。这是一个有多个待办事项列表可供选择的待办事项应用程序。我想要的行为是一个Todo列表列表,您可以在其中选择一个和Todo项(如wunderlist/msft Todo)。选择一个不同的列表,它的todo items show等等。此时,它使用静态json,其中每个项都有一个子数组 useEffect-我正试图使用它来加载数据。它不断抱怨缺少依赖项。当我添加它们时,它也会对此抱怨。如果我对第二个参数使用and empty array,它会抱怨,并且似乎会多次触发 useState-我正在使用它来存储数据。它被初始化为一个空数组。但render是在useEffect之前触发的,它表示我的数据未定义,所以我的第二个列表从不渲染 我在代码中有几个console.log,它们都会触发多次 我敢肯定这只是noob的错误,但在这一点上我很难堪。这是我的密码: data/Todo.jsJavascript 反应:将行为与useEffect和/或useState挂钩混淆,javascript,reactjs,Javascript,Reactjs,这里是诺布。我正在尝试制作一个简单的练习应用程序来帮助我的反应学习,我得到了很多奇怪的行为。这是一个有多个待办事项列表可供选择的待办事项应用程序。我想要的行为是一个Todo列表列表,您可以在其中选择一个和Todo项(如wunderlist/msft Todo)。选择一个不同的列表,它的todo items show等等。此时,它使用静态json,其中每个项都有一个子数组 useEffect-我正试图使用它来加载数据。它不断抱怨缺少依赖项。当我添加它们时,它也会对此抱怨。如果我对第二个参数使用an
const TodoData=[
{
Id:1,
标题:“食品杂货”,
托多利斯特:[
{
Id:1,
标题:“苹果”
},
{
Id:2,
标题:“橙子”
},
{
Id:3,
标题:“香蕉”
}
]
},
{
Id:2,
标题:“日常任务”,
托多利斯特:[
{
Id:11,
标题:“清洁厨房”
},
{
Id:12,
标题:“饲养宠物”
},
{
Id:13,
标题:“做事”
}
]
},
{
Id:3,
标题:“五金店”,
托多利斯特:[]
},
{
Id:4,
标题:“好市多”,
托多利斯特:[
{
Id:21,
标题:“尿布”
},
{
身份证号码:22,
标题:“猫粮”
},
{
Id:23,
标题:“苹果”
},
{
Id:24,
标题:“香蕉”
}
]
},
{
Id:5,
标题:“工作”,
托多利斯特:[
{
Id:34,
标题:“TPS报告”
}
]
}
];
将默认值导出到OData代码>Q:useffect-我正试图使用它来加载数据。它不断抱怨缺少依赖项
A:您可以通过eslint(react hooks/deps)忽略它
,无需担心
Q: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>
)
}
//您正在使用数组初始化'todoDetails',此时将出现对象
//因此,在html/jsx内部映射时会出现错误
//const[todoDetails,settodetails]=useState([]);
//init带有'null',为什么?
const[todoDetails,settodetails]=useState(null);
//这样你就可以做这样的事情
{
todoDetails&(//(
{details.Title}
))}
)
}
Q:现在您将获得多个控制台.log
A:这背后的原因是
React可以在提交之前多次调用呈现阶段生命周期,也可以在根本不提交的情况下调用它们(由于错误或更高优先级的中断)
我已经从演示中的index.js
中删除了它,所以您可以看到它的差异
工作演示:
您必须将getToData的逻辑放入useffect
钩子中
useEffect(() => {
const getTodoData = () => {
setTodoData(TodoData);
console.log("getting todo data");
getTodoDetails(1);
};
if (todoData.length === 0) {
getTodoData();
}
}, [todoData.length]);
以及在渲染中
{
//检查todoDetails是否有TodoList
todoDetails.TodoList&&
todoDetails.TodoList.map((详细信息)=>(
{details.Title}
));
}
以下是更新后的您评论并说失败的代码是由于todoDetails造成的。TodoList
在第一次呈现组件时可能未定义。为了避免这种情况,可以使用一个项目初始化todoDetails
,或者在调用.map
之前检查todoDetails.TodoList
是否已定义
{todoDetails.TodoList ? todoDetails.TodoList.map(details => (
<li className="list-group-item" key={details.Id}>
{details.Title}
</li>
)) : null}
不要太担心eslint(react hooks/deps)
错误。您需要了解useffect
的第二个参数的含义。在代码中,您将todoData
传递给useffect
:
useEffect(() => {
if (todoData.length === 0) {
getTodoData();
}
}, [todoData]);
这意味着,每当todoData
更改时,useffect
将运行,其行为类似于componentdiddupdate
。如果您只传递一个空数组,这意味着您的useEffect没有依赖项,它将只执行一次,其行为类似于componentDidMount
。所以,你在这里做的很好
除此之外,我还可以给您一些关于代码的提示:
关于handleClick
函数,您可以删除它,然后简单地调用getTodoDetails(id)
传递id,而不是将其添加到数据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>
您正在将您的作为对象进行详细建模
,并将其初始化为数组
。如果todetails
始终只有一个todo,请将其初始化为对象,这样可以防止从数组访问todetails.Title
。渲染后将始终执行useffect
const [todoDetails, setTodoDetails] = useState({});
useffect
钩子有时会很奇怪。要修复它,只需直接传入getToData
函数,如下所示:
const gettodata=()=>{
setTodoData(TodoData);
log(“获取待办事项数据”);
getTodoDetails(1);
};
useffect(gettodata,[]);
const getTodoDetails = id => {
const result = TodoData.find(x => x.Id === id);
console.log(result);
setTodoDetails(result);
};
const [todoDetails, setTodoDetails] = useState({});
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;