Reputation: 11
We thing that it will take good perfomance. Elems will't rerender.
function App() {
const [items, setItems] = useState(() => [<Counter key={0} i={0} />]);
const onClick = () => {
setItems([...items, <Counter key={items.length} i={items.length} />]);
};
return (
<div className="App" onClick={onClick}>
<h1>Hello CodeSandbox</h1>
{items}
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
function Counter({ i }) {
console.log(`render ${i}`);
return <h2>{i}</h2>;
}
For better understanding I make an example in the codesandbox: https://codesandbox.io/s/busy-austin-qbtpm
Upvotes: 1
Views: 191
Reputation: 39310
To prevent renders you can use pure component or use React.memo and make sure you never pass a new reference as prop by using useCallback or useMemo. Here is an example:
const id = (i => () => ++i)(0);
function App() {
const [items, setItems] = React.useState([]);
const addCounter = React.useCallback(
() =>
setItems(items =>
items.concat({
id: id(),
count: 0,
})
),
[]
);
const add = React.useCallback(
id =>
setItems(items =>
items.map(item =>
item.id === id
? { ...item, count: item.count + 1 }
: item
)
),
[]
);
return (
<div>
<button onClick={addCounter}>Add counter</button>
{items.map(item => (
<Counter item={item} key={item.id} add={add} />
))}
</div>
);
}
const Counter = React.memo(function Counter({ item, add }) {
console.log(`render ${item.id}`);
return (
<button onClick={() => add(item.id)}>
{item.count}
</button>
);
});
//render app
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 1606
Is not a good idea to store jsx in the state like Shawn Yap said. But also in general with javascript this is a bad practice. In this case it is more complicated than needed. A good idea is to keep data as simple and lightweight as it can be and then add to it when needed. In this example theres a few improvements you can do
// You used both function App() & const onClick = () =>
// Best to choose one and stick with it.
const App = () => {
const [items, setItems] = useState([]);
const onClick = () => {
setItems([
...items,
items.length
]);
};
return (
<div className="App" onClick={onClick}>
<h1>Hello CodeSandbox</h1>
// Instead use a map to render items, you also don't need another function for this
{items.map((item, index) => {
console.log("rendered item with index: ", index)
return <h2 key={index}>{index}</h2>
})}
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
Also never store the key of an item, the key of an item with be based off the index. Although they may look the same if you delete an item in your example and then add a new item you will have an error.
[1, 3, 3]
would have cased it to error out for you. [1, 3, 3]
using the index of the array as the key will not error out.
Hope that helps and happy coding :)
Upvotes: 1