代码之家  ›  专栏  ›  技术社区  ›  pareshaann

由于useEffect钩子,在react中无限重渲染

  •  0
  • pareshaann  · 技术社区  · 1 年前

    我用State hook todos 阵列

    const [todos, setTodos] = useState([]);
    

    我使用这个数组来显示和索引所有待办事项。我还需要初始挂载的待办事项,所以我使用useEffect钩子。

    useEffect(() => {
      const getTodoData = async () => {
        const { data } = await axios.get(`${BASE_URL}/todos`);
        setTodos(data);
      };
      getTodoData();
    }, [todos]);
    

    然而,上述代码会生成无限的重解释器,并向以下对象发出无限的请求 ${BASE_URL}/todos .

    我理解为什么会发生这种情况。如果我错了,请纠正我,但我认为当我 setTodos(data); 这个 待办事项 数组变化,即状态变化,即依赖关系 useEffect [todos] 变化。因此,setup函数运行,它发出请求,并且 setTodos(数据); 再一次。因此,无限循环。

    我看到了其他与此相关的帖子,几乎每个人都说要删除依赖关系。但我不明白的是,如果我们要删除依赖关系,那么在创建新的todo后,我们必须刷新页面以查看所反映的更改。我认为这不可行。

    如果有办法让新的待办事项出现在页面上而不刷新。

    2 回复  |  直到 1 年前
        1
  •  0
  •   Sean Yasnogorodski    1 年前

    我认为你错过了一步,这就是你遇到这个问题的原因。

    你有一个待办事项数组,这很好,有了这个数组,你可以显示你的待办事项。

    现在是思考的部分——数组什么时候会改变? 我可以想到这样的场景:

    1. 待办事项的初始加载
    2. 添加新待办事项
    3. 删除现有待办事项

    你缺少的一步是将这些场景分开。 你想得到这样的东西:

    const [todos, setTodos] = useState([]);
    
    useEffect(() => {
       const getTodoData = async () => {
         const { data } = await axios.get(`${BASE_URL}/todos`);
         setTodos(data);
       };
       getTodoData();
    }, []); // This use effect will do scenario 1
    
    // Use this function to create new todo
    const addTodo = (newTodo) => {
      const { data } = await axios.post(`${BASE_URL}/todos`, { newTodo });
      
      // assuming the returned data is all todos from the backend
      setTodos(data);
    }
    
    // Use this function to remove existing todo
    const removeTodo = (existingTodoId) => {
      const { data } = await axios.delete(`${BASE_URL}/todos/${existingTodoId}`);
    
      // assuming the returned data is all todos from the backend
      setTodos(data);
    }
    

    这样做,你就不会遇到无限重理解的问题,而且你的数据也会保持更新。

    附笔 我建议你使用 @tanstack/react-query 库来处理这种请求,它将使您的代码更清晰、更易于使用。

        2
  •  0
  •   Deepesh Jain    1 年前

    你对无限循环发生的原因的理解是绝对正确的。问题的产生是因为 todos 数组作为依赖项包含在 useEffect 钩子,所以每次 setTodos 当被调用时,todos状态会发生变化,从而触发 使用效果 再次,这导致了无限的重复。

    解决方案:

    从依赖数组中删除todos:为了在初始挂载时获取数据,您只需要一个空的依赖数组[],这样组件挂载时效果只运行一次。

    处理新待办事项而不刷新: 为了在不刷新页面的情况下处理新待办事项的添加,您应该在创建新待办事项后直接更新待办事项状态。这样,新的todo将立即显示。

    以下是调整代码的方法:

    import { useState, useEffect } from 'react';
    import axios from 'axios';
    
    const TodosComponent = () => {
      const [todos, setTodos] = useState([]);
    
      useEffect(() => {
        const getTodoData = async () => {
          try {
            const { data } = await axios.get(`${BASE_URL}/todos`);
            setTodos(data);
          } catch (error) {
            console.error('Error fetching todos:', error);
          }
        };
        getTodoData();
      }, []); // Empty array ensures this runs only once on mount
    
      const addTodo = async (newTodo) => {
        try {
          const { data } = await axios.post(`${BASE_URL}/todos`, newTodo);
          setTodos((prevTodos) => [...prevTodos, data]); // Update the state with the new todo
        } catch (error) {
          console.error('Error adding new todo:', error);
        }
      };
    
      return (
        <div>
          {/* Render todos and other UI elements */}
        </div>
      );
    };
    
    export default TodosComponent;
    

    说明:

    1. 使用效果 使用空依赖数组:
      • 通过传递一个空数组[]作为依赖数组,该效果将只在组件首次挂载时运行一次。这可以防止无限循环。
    2. addTodo 功能:
      • 这个 addTodo 函数处理添加新todo。成功将新todo添加到后端后,新todo将附加到现有todo 待办事项 国家使用 setTodos 功能。这允许新的todo立即反映在UI中,而无需刷新页面。

    处理更新或删除

    如果你需要处理更新或删除,你可以按照类似的方法更新 待办事项 相应地陈述:

    • 用于更新待办事项 ,在状态数组中找到todo,修改它,然后用更新的数组设置状态。
    • 用于删除待办事项 ,从状态数组中过滤出todo,并使用过滤后的数组设置状态。

    这种方法可确保您的UI与后端数据保持同步,而无需刷新页面。