0

I'm trying to improve the performance of a long list with changeable items using React.memo, but I'm getting strange behavior.

Steps to reproduce:

1 - Go to the sandbox here

2 - Press add on the first item

3 - Press add on the second item

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;
rayashi
  • 1,721
  • 3
  • 20
  • 28

2 Answers2

1

I have modified your add function. And have added the key attribute to the item or the li element as that helps react determine which element has changed in the 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>
0

Solved it by using the latest state of list

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>
  );
};

Also added key as stated by Ngọc Hy

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

iunfixit
  • 953
  • 3
  • 15