Reputation: 634
I'm trying to get my head around the way React renders list items.
I have boiled my question down to some very simple code (shown below) (sandbox here). It's just a list of 3 items and a button that appends 3 more items to the end of this list.
I want to prevent React from rerendering the first three items when the extra items are added. Initially I thought this was done automatically if I've set my "keys" properly, which I believe I have. This didn't work so I tried wrapping the list component in React.memo
. But the console shows that I'm still rerendering 6 items when I expect to only be rendering the 3 extra items.
Why is this? I feel like possibly it's something to do with me mutating the arr
array that contains the item when I set the state with setArr
, and perhaps there is a method to prevent this. But I'm at a loss of what it is. What am I doing wrong?
Thanks in advance.
import React, { memo, useState } from "react";
export default function App() {
const [arr, setArr] = useState(["a", "b", "c"]);
const addItem = () => {
const extraItems = ["d", "e", "f"];
setArr((arr) => [...arr, ...extraItems]);
};
const SimpleComponent = memo(({ text }) => {
console.log("Rendered ", text);
return <li>{text}</li>;
}, true);
return (
<div className="App">
<ul>
{arr.map((item) => {
return <SimpleComponent key={item} text={item} />;
})}
</ul>
<button onClick={() => addItem()}>Add more</button>
</div>
);
}
Upvotes: 0
Views: 241
Reputation: 5036
The problem is your memo is inside the component, so it gets re-created on each render, which makes it all pointless, the momoized component needs to be outside the component that uses it, try
const SimpleComponent = memo(({ text }) => {
console.log("Rendered ", text);
return <li>{text}</li>;
});
export default function App() {
const [arr, setArr] = useState(["a","b","c"]);
const addItem = () => {
const extraItems = ["d", "e", "f"];
setArr((arr) => [...arr, ...extraItems]);
};
return (
<div className="App">
<ul>
{arr.map((item) => {
return <SimpleComponent key={item} text={item} />;
})}
</ul>
<button onClick={() => addItem()}>Add more</button>
</div>
);
}
Upvotes: 2