使用React Context和useReducer防止在todo应用中重新渲染未更改的项目

时间:2019-11-04 11:56:07

标签: javascript reactjs

我正在使用context和useReducer创建一个简单的React todo应用程序,并且我不确定在其中一项更改时如何防止每个待办事项重新渲染。当一个待办事项更改时,将分派一个动作,从而导致状态更新。具体地说,reduce返回一个待办事项已更新而其他待办事项相同的状态的新副本。

鉴于状态会发生变化,因此在更新一个待办事项时重新渲染所有待办事项是有意义的。但是,我的待办事项组件将必要的道具传递给每个待办事项-并且这些道具不会更改-因此我认为不必更改道具的todo组件不会重新渲染。取而代之的是,当我使用开发工具并选中突出显示重新渲染的框时,我看到它们全部闪烁。我想念什么?

// from the reducer
    case "EDIT_TODO":
      return state.map(todo => {
        if (todo.id === action.payload.id) {
          return {
            ...todo,
            desc: action.payload.value
          };
        } else {
          return todo;
        }
      });
    default:
      return state;
// from the todos component
<ul className="TodosApp">
    {todos.map(todo => (
        <li key={todo.id}>
            <Todo
              id={todo.id}
              complete={todo.complete}
              description={todo.desc}
            />
       </li>
    ))}
</ul>
// from the todo component
// handleToggleTodo function dispatches an "EDIT_TODO" action
const EditTodo = ({ id, description, complete }) => {
    // not showing the handleToggleTodo function, which dispatches an "EDIT_TODO" action
    // and has a payload with the todo id and the updated todo description.
    return (
      <Fragment>
        <input type="checkbox" checked={complete} onChange={handleToggleTodo} />
        <input
           className="Todo-input"
           type="text"
           value={description}
           onChange={handleChange}
        />
      </Fragment>
   )

我的工作在codeandbox中,https://codesandbox.io/s/determined-fire-8hirp?fontsize=14

1 个答案:

答案 0 :(得分:2)

您可以使用React memo()方法。

https://dmitripavlutin.com/use-react-memo-wisely/

您需要将无状态组件包装为react备忘录,并且如果props相同,则不会重新渲染该组件。

import React from "react";
import { useTodosState } from "./todos_context";
import Todo from "./todo";

const Todos = () => {
  const todos = useTodosState();
  return (
    <>
      <h2>Todos</h2>
      <ul className="TodosApp">
        {todos.map(todo => (
          <li key={todo.id}>
            <Todo
              id={todo.id}
              complete={todo.complete}
              description={todo.desc}
            />
          </li>
        ))}
      </ul>
    </>
  );
};

const MemoizeTodos = React.memo(Todos);

export default MemoizeTodos;
  

在决定更新DOM时,React首先渲染您的组件,然后渲染   将结果与先前的渲染结果进行比较。如果渲染   结果不同,React更新了DOM。

     

当前与以前的渲染结果比较很快。但是你可以   在某些情况下可以加快流程。

     

将组件包装在React.memo()中时,React会渲染   组件并记住结果。在下一次渲染之前,如果新   道具是一样的,React重复使用记忆的结果,跳过下一个   渲染。