使用 useEffect 钩子停止导致无限循环的反应
Stop react causing an infinite loop using useEffect hook
我对反应和节点还很陌生,我已经设法为一个简单的待办事项列表创建了一个 API。我已经从 api 中获取数据并将其显示在屏幕上。
如果我在 useEffect()
挂钩上将依赖项数组留空,它将只呈现一次并且不会循环。但是如果我添加一个新的待办事项,除非我刷新,否则它不会更新列表。所以我将 todos 状态放入依赖项数组,然后在我添加新项目时显示它,但是如果我查看开发工具中的网络选项卡,它会在无限循环中点击 api。我做错了什么?
代码如下:
应用程序
import React, { useState, useEffect } from "react";
import Todo from "./components/Todo";
import Heading from "./components/Heading";
import NewTodoForm from "./components/NewTodoForm";
const App = () => {
const [todos, setTodos] = useState([]);
useEffect(() => {
const getTodos = async () => {
const res = await fetch("http://localhost:3001/api/todos");
const data = await res.json();
setTodos(data);
};
getTodos();
}, []);
return (
<div className="container">
<Heading todos={todos} />
<section className="todos-container">
<ul className="todos">
{todos.map((todo) => (
<Todo key={todo._id} todo={todo} />
))}
</ul>
</section>
<section className="todo-form">
<NewTodoForm />
</section>
</div>
);
};
export default App;
标题
import React from "react";
const Heading = ({ todos }) => (
<header>
<h1>Todos</h1>
<p>
{todos.length} {todos.length === 1 ? "Item" : "Items"}
</p>
</header>
);
export default Heading;
待办事项
import React, { useState } from "react";
const Todo = ({ todo }) => (
<li>
{todo.name}
<input type="checkbox" />
</li>
);
export default Todo;
NewTodoForm
import React, { useState } from "react";
import { Plus } from "react-feather";
const NewTodoForm = () => {
const [formData, setFormData] = useState({
name: "",
completed: false,
});
const { name } = formData;
const handleOnChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const handleSubmit = async (e) => {
e.preventDefault();
await fetch("http://localhost:3001/api/todos", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
});
setFormData({
name: "",
completed: false,
});
};
return (
<form onSubmit={handleSubmit}>
<div className="form-control">
<Plus className="plus" />
<input
name="name"
type="text"
placeholder="Add New Item"
onChange={handleOnChange}
value={name}
/>
<button>Add</button>
</div>
</form>
);
};
export default NewTodoForm;
如果我注释掉所有组件并且只有 App 组件,当我将待办事项添加到 useEffect()
挂钩的依赖数组时它仍然无限循环。
因此,与其将其作为依赖项,不如将函数写在 useEffect
之外,这样您就可以在添加待办事项后调用该函数
示例:
const getTodos = async () => {
const res = await fetch("http://localhost:3001/api/todos");
const data = await res.json();
setTodos(data);
};
useEffect(() => {
getTodos();
}, []);
所以 getTodos
最初只会 运行 一次,并且 运行 只会在 Todo
的 onSubmit
或 onClick
上再次出现 运行,所以,只需调用 getTodos
函数 onSubmit 或 onClick
我对反应和节点还很陌生,我已经设法为一个简单的待办事项列表创建了一个 API。我已经从 api 中获取数据并将其显示在屏幕上。
如果我在 useEffect()
挂钩上将依赖项数组留空,它将只呈现一次并且不会循环。但是如果我添加一个新的待办事项,除非我刷新,否则它不会更新列表。所以我将 todos 状态放入依赖项数组,然后在我添加新项目时显示它,但是如果我查看开发工具中的网络选项卡,它会在无限循环中点击 api。我做错了什么?
代码如下:
应用程序
import React, { useState, useEffect } from "react";
import Todo from "./components/Todo";
import Heading from "./components/Heading";
import NewTodoForm from "./components/NewTodoForm";
const App = () => {
const [todos, setTodos] = useState([]);
useEffect(() => {
const getTodos = async () => {
const res = await fetch("http://localhost:3001/api/todos");
const data = await res.json();
setTodos(data);
};
getTodos();
}, []);
return (
<div className="container">
<Heading todos={todos} />
<section className="todos-container">
<ul className="todos">
{todos.map((todo) => (
<Todo key={todo._id} todo={todo} />
))}
</ul>
</section>
<section className="todo-form">
<NewTodoForm />
</section>
</div>
);
};
export default App;
标题
import React from "react";
const Heading = ({ todos }) => (
<header>
<h1>Todos</h1>
<p>
{todos.length} {todos.length === 1 ? "Item" : "Items"}
</p>
</header>
);
export default Heading;
待办事项
import React, { useState } from "react";
const Todo = ({ todo }) => (
<li>
{todo.name}
<input type="checkbox" />
</li>
);
export default Todo;
NewTodoForm
import React, { useState } from "react";
import { Plus } from "react-feather";
const NewTodoForm = () => {
const [formData, setFormData] = useState({
name: "",
completed: false,
});
const { name } = formData;
const handleOnChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const handleSubmit = async (e) => {
e.preventDefault();
await fetch("http://localhost:3001/api/todos", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
});
setFormData({
name: "",
completed: false,
});
};
return (
<form onSubmit={handleSubmit}>
<div className="form-control">
<Plus className="plus" />
<input
name="name"
type="text"
placeholder="Add New Item"
onChange={handleOnChange}
value={name}
/>
<button>Add</button>
</div>
</form>
);
};
export default NewTodoForm;
如果我注释掉所有组件并且只有 App 组件,当我将待办事项添加到 useEffect()
挂钩的依赖数组时它仍然无限循环。
因此,与其将其作为依赖项,不如将函数写在 useEffect
之外,这样您就可以在添加待办事项后调用该函数
示例:
const getTodos = async () => {
const res = await fetch("http://localhost:3001/api/todos");
const data = await res.json();
setTodos(data);
};
useEffect(() => {
getTodos();
}, []);
所以 getTodos
最初只会 运行 一次,并且 运行 只会在 Todo
的 onSubmit
或 onClick
上再次出现 运行,所以,只需调用 getTodos
函数 onSubmit 或 onClick