【问题标题】:Is there a way for my useEffect hook to rerender right away when my state changes?当我的状态改变时,我的 useEffect 钩子有没有办法立即重新渲染?
【发布时间】:2020-11-17 00:06:05
【问题描述】:

我有一个 todos 状态,它是一个空数组。我将一个对象添加到 todos 状态,并将所有添加的 todos 的属性已完成设置为 false。


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

const [todoForm, setTodoForm] = useState({
    id: null,
    task: '',
    completed: false,
    time: '',
  });

这是我用来更新待办事项的 useEffect 钩子

 useEffect(() => {
    const sortedArray = todos.sort((a, b) => b.completed - a.completed);
    setTodos(sortedArray);
  }, [todos, todos.completed]);
const toggleComplete = (id) => {
    setTodos(
      todos.map((todo) => {
        if (todo.id === id) {
          return {
            ...todo,
            completed: !todo.completed,
          };
        }
        return todo;
      })
    );
  };

问题是,当我第一次单击待办事项并完成时,它并没有一直到顶部。这是一张图片:

直到我像这样单击另一个它才会重新呈现

【问题讨论】:

    标签: reactjs react-hooks use-effect


    【解决方案1】:

    问题

    排序是一种就地排序,这意味着它会改变状态对象。

    Array.prototype.sort

    sort() 方法对数组元素进行就地排序并返回 排序后的数组。

    解决方案

    在处理程序中切换“已完成”状态时对数组进行排序。先复制todos数组,这样就有了新的状态数组引用,然后排序。

    const toggleComplete = (id) => {
      setTodos((todos) =>
        todos
          .map((todo) => {
            if (todo.id === id) {
              return {
                ...todo,
                completed: !todo.completed
              };
            }
            return todo;
          })
          .sort((a, b) => b.completed - a.completed)
      );
    };
    

    【讨论】:

    • 我没有测试过这个,但乍一看这会造成循环吗? setTodos 将 todos 更新为一个新的引用,该引用又会再次触发 useEffect。您的回答是正确的,但我假设数组排序不会成为全部问题。
    • 嗯,当我单击其中一个复选框时,我的应用程序冻结了。我确实有一个切换复选框的功能。也许这会导致它冻结
    • 或者像@JacobSmit 所说的那样创建一个循环
    • @EirikVattøy 拍摄,完全正确。我猜你应该在更新状态时进行排序,即将待办事项切换为“已完成”时,反之亦然。您可以使用切换处理程序更新您的问题吗?
    • @EirikVattøy 更新了答案。很抱歉第一个版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多