如何在使用 useReducer 时在 React JS 中进行优化,循环传递给子组件的状态

How to optimize in react js while working with useReducer, looped over state which is passed to child component

我正在尝试创建待办事项列表。

function App() {
  return (
    <div className="App">
      <UseReducerToDo/>
    </div>
  );
}

const { useReducer, useState } = React;

const reducer = (state, action) => {
  return [...state, { id: Date.now(), ToDo: action, completed: false }];
};

function UseReducerToDo() {
  const [state, dispatch] = useReducer(reducer, []);
  const [Todo, setTodo] = useState("");

  const addToTODO = (e) => {
    e.preventDefault();
    dispatch(Todo);
  };

  return (
    <div>
      <form onSubmit={addToTODO}>
        <input
          type="text"
          value={Todo}
          onChange={(e) => setTodo(e.target.value)}
        ></input>
      </form>
      {state.length > 0
        ? state.map((todo) => <DispToDo key={todo.id} todo={todo} />)
        : "no pending items"}
    </div>
  );
}

function DispToDo({ todo }) {
  console.log("DispToDo", todo);
  return (
    <div>
      <p>
        {todo.ToDo + "->"} status {todo.completed ? "done" : "pending"}
      </p>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

现在,代码可以编译并运行良好。问题与性能有关。

应用程序运行时

添加并提交第一个元素时

现在真正的问题出现了

我发现文本框中的每个按键都会刷新子组件 DispToDo。这是显而易见的,因为每次按键时控制台中的日志都会累加。

state 中没有变化,但 DispToDo 中有刷新。

有什么办法可以优化吗?

尝试渲染 memoized component:

const MemoDispToDo = React.memo(DispToDo);

// ...
.map(todo => <MemoDispToDo key={todo.id} todo={todo} />)

您可以使用 useMemo() 挂钩记忆您的 state.map()

const todos = useMemo(() => (
  state.map((todo) => <DispToDo key={todo.id} todo={todo} />)
), [state]);

查看下面的完整演示:

function App() {
  return (
    <div className="App">
      <UseReducerToDo/>
    </div>
  );
}

const { useMemo, useReducer, useState } = React;

const reducer = (state, action) => {
  return [...state, { id: Date.now(), ToDo: action, completed: false }];
};

function UseReducerToDo() {
  const [state, dispatch] = useReducer(reducer, []);
  const [Todo, setTodo] = useState("");

  const addToTODO = (e) => {
    e.preventDefault();
    dispatch(Todo);
  };
  
  const todos = useMemo(() => (
    state.map((todo) => <DispToDo key={todo.id} todo={todo} />)
  ), [state]);

  return (
    <div>
      <form onSubmit={addToTODO}>
        <input
          type="text"
          value={Todo}
          onChange={(e) => setTodo(e.target.value)}
        ></input>
      </form>
      {state.length > 0 ? todos : "no pending items"}
    </div>
  );
}

function DispToDo({ todo }) {
  console.log("DispToDo", todo);
  return (
    <div>
      <p>
        {todo.ToDo + "->"} status {todo.completed ? "done" : "pending"}
      </p>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>