首页 > 解决方案 > 更新大列表的一个元素而不在反应钩子中重新渲染其他元素?

问题描述

我想通过测试li 一个简单的待办事项列表的大列表来优化我的反应应用程序。

例如,当点击 a 时li,任务将被直通,并且检查图标将变为绿色。这个简单的动作对于一个大列表来说非常慢,因为整个列表都是重新渲染的。

如何使用 React Hooks 做到这一点?

function App() {
  const [list, setList] = useState([]);
  const [input, setInput] = useState("");

  const inputRef = useRef(null);
  useEffect(() => inputRef.current.focus(), []);

//Pseudo Big List
  useEffect(() => {
    const test = [];
    let done = false;
    for (let i = 0; i < 5000; i++) {
      test.push({ task: i, done });
      done = !done;
    }
    setList(test);
  }, []);

  const handlerSubmit = (e) => {
    e.preventDefault();

    const newTask = { task: input, done: false };
    const copy = [...list, newTask];

    setList(copy);
    setInput("");
  };

  const checkHandler = (e, index) => {
    e.stopPropagation();
    const copy = [...list];
    copy[index].done = !copy[index].done;
    setList(copy);
  };

  const suppression = (e, index) => {
    e.stopPropagation();
    const copy = [...list];
    copy.splice(index, 1);
    setList(copy);
  };

  const DisplayList = () => {
    return (
      <ul>
        {list.map((task, index) => (
          <Li
            key={index}
            task={task}
            index={index}
            suppression={suppression}
            checkHandler={checkHandler}
          />
        ))}
      </ul>
    );
  };

  //JSX
  return (
    <div className='App'>
      <h1>TODO JS-REACT</h1>

      <form id='form' onSubmit={handlerSubmit}>
        <input
          type='text'
          placeholder='Add task'
          required
          onChange={(e) => setInput(e.target.value)}
          value={input}
          ref={inputRef}
        />
        <button type='submit'>
          <i className='fas fa-plus'></i>
        </button>
      </form>

      {list.length === 0 && <div id='noTask'>No tasks...</div>}

      <DisplayList />
    </div>
  );
}

export default App;

锂成分

import React from "react";

export default function Li(props) {
  return (
    <li
      onClick={(e) => props.checkHandler(e, props.index)}
      className={props.task.done ? "line-through" : undefined}
    >
      {props.task.task}
      <span className='actions'>
        <i className={`fas fa-check-circle ${props.task.done && "green"}`}></i>
        <i
          className='fas fa-times'
          onClick={(e) => props.suppression(e, props.index)}
        ></i>
      </span>
    </li>
  );
}

这里的代码沙盒: https ://codesandbox.io/s/sad-babbage-kp3md ?file=/src/App.js

标签: reactjsoptimizationreact-hooksuse-staterenderer

解决方案


您可以使用React.memo和包装Li组件。Li这将基于浅比较缓存组件的实例。在文档中阅读更多内容

否则,如果您不需要容器中的状态,您可以将其本地保存在Li组件中,这样就不会导致整个列表重新渲染。


推荐阅读