【问题标题】:Stop react causing an infinite loop using useEffect hook使用 useEffect 钩子停止反应导致无限循环
【发布时间】:2020-10-27 20:22:58
【问题描述】:

我是 react 和 node 的新手,我已经设法为简单的待办事项列表创建了一个 API。我已经从 api 获取数据并将其呈现在屏幕上。

如果我在 useEffect() 挂钩上将依赖项数组留空,它只会呈现一次并且不会循环。但是如果我添加一个新的 Todo,它不会更新列表,除非我刷新。所以我将 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 组件,当我将 todos 添加到 useEffect() 挂钩的依赖项数组时,它仍然是无限循环。

【问题讨论】:

  • 它将陷入无限循环,因为您在 useEffect 中设置 todo 并提供与依赖项相同的内容
  • 将此 getTodos 移到您的 useEffect 之外
  • 当你添加一个新的待办事项时,它并不好获取所有的待办事项,你只需要获取新创建的待办事项,所以你可能需要改变你的思维方式,要么你可以保存待办事项作为 savetodo 函数的返回并将其添加到现有的 todos 状态,或者获取您需要的唯一 todo 作为单独的请求

标签: javascript reactjs react-hooks infinite-loop


【解决方案1】:

因此,不要将其作为依赖项写入 useEffect 之外的函数,以便在添加待办事项后调用该函数

例子:

  const getTodos = async () => {
      const res = await fetch("http://localhost:3001/api/todos");
      const data = await res.json();
      setTodos(data);
    };

 useEffect(() => {
    getTodos();
  }, []);

所以getTodos最初只会运行一次,并且只会在TodoonSubmitonClick上再次运行,所以,只需调用getTodos函数onSubmit或onClick

【讨论】:

    猜你喜欢
    • 2021-04-10
    • 2020-03-25
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    相关资源
    最近更新 更多