Let's say I have:
const AddItemButton = React.memo(({ onClick }) => {
// Goal is to make sure this gets printed only once
console.error('Button Rendered!');
return <button onClick={onClick}>Add Item</button>;
});
const App = () => {
const [items, setItems] = useState([]);
const addItem = () => {
setItems(items.concat(Math.random()));
}
return (
<div>
<AddItemButton onClick={addItem} />
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
</div>
);
};
Any time I add an item, the <AddItemButton />
gets re-rendered because addItem is a new instance. I tried memoizing addItem:
const addItemMemoized = React.memo(() => addItem, [setItems])
But this is reusing the setItems from the first render, while
const addItemMemoized = React.memo(() => addItem, [items])
Doesn't memoize since items
reference changes.
I can'd do
const addItem = () => {
items.push(Math.random());
setItems(items);
}
Since that doesn't change the reference of items
and nothing gets updated.
One weird way to do it is:
const [, frobState] = useState();
const addItemMemoized = useMemo(() => () => {
items.push(Math.random());
frobState(Symbol())
}, [items]);
But I'm wondering if there's a better way that doesn't require extra state references.
By default, when we call this method, the component re-renders once it receives new props, even though the props have not changed. To prevent the render method from being called, set the return to false, which cancels the render. This method gets called before the component gets rendered.
React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.
If you don't want a component to re-render when its parent renders, wrap it with memo. After that, the component indeed will only re-render when its props change.
The current preferred route is useCallback
, which is the same as your useMemo
solution, but with additional possible optimizations in the future. Pass an empty array []
to make sure the function will always have the same reference for the lifetime of the component.
Here, you also want to use the functional state update form, to make sure the item is always being added based on the current state.
const addItem = useCallback(() => {
setItems(items => [...items, Math.random()]);
}, []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With