避免重新渲染未更改的项目

Avoiding re-render unchanged items

我正在尝试使用 React.memo 提高包含可更改项目的长列表的性能,但我遇到了奇怪的行为。

重现步骤:

1 - 转到沙盒 here

2 - 在第一项上按添加

3 - 在第二个项目上按添加

import React, { useState } from "react";

const App = () => {
  const [list, setList] = useState([
    { id: 1, qtd: 0 },
    { id: 2, qtd: 0 },
    { id: 3, qtd: 0 },
    { id: 4, qtd: 0 }
  ]);

  const onAdd = (id, qtd) => {
    setList(
      list.map((item) => {
        if (item.id === id) {
          return { ...item, qtd };
        } else {
          return item;
        }
      })
    );
  };

  return (
    <ul>
      {list.map((item) => (
        <Item {...item} onChange={onAdd} />
      ))}
    </ul>
  );
};

const Item = React.memo(({ id, qtd, onChange }) => {
  console.log("Rendering -> " + id);

  return (
    <li>
      <span>{qtd}</span>
      <button onClick={() => onChange(id, qtd + 1)}>Add</button>
    </li>
  );
}, areEqual);

function areEqual(prev, next) {
  return prev.qtd === next.qtd;
}

export default App;

使用列表的最新状态解决了

const App = () => {
  const [list, setList] = useState([
    { id: 1, qtd: 0 },
    { id: 2, qtd: 0 },
    { id: 3, qtd: 0 },
    { id: 4, qtd: 0 }
  ]);

  const onAdd = (id, qtd) => {
    setList((l) =>
      l.map((item) => {
        if (item.id === id) {
          return { ...item, qtd };
        } else {
          return item;
        }
      })
    );
  };

  return (
    <ul>
      {list.map((item) => (
        <Item key={item.id} {...item} onChange={onAdd} />
      ))}
    </ul>
  );
};

还添加了 Ngọc Hy 所述的密钥

https://codesandbox.io/s/flamboyant-grothendieck-z8uxf?file=/src/App.js

我修改了你的添加功能。并将 key 属性添加到项目或 li 元素,因为这有助于反应确定 DOM.

中哪个元素已更改
const onAdd = (id, qtd) => {
    const oldList = [...list];
    oldList.forEach((element) => {
      if (element.id === id) {
        element.qtd=qtd;
      }
    });
    setList(oldList);
  };

    <ul>
      {list.map((item) => (
        <Item key={item.id} {...item} onChange={onAdd} />
      ))}
    </ul>