As the title says, does it make sense to pass objects or arrays into dependency arrays in React?
I can see from the React documentation that the useMemo
hook uses the Object.is( )
algorithm for comparison. So the comparison will always return false for arrays and objects and the code inside the memo will re run.
If you have an object with primitive values such as string an numbers I guess it would make sense to destructure the properties and pass them in right?
But what if the object has non primitive values such as arrays, other objects or functions? What would be a good refactor path to be able to use useMemo
in this situation?
Thank you!
CodePudding user response:
So the comparison will always return false for arrays and objects
If you're creating a new array/object each time, then that's true. But there are many cases where that is not true. If you have a stable reference to an array/object you can absolutely pass arrays and objects into useMemo. For example, here's a classic case: calculating a sorted array based on state.
const Example = () => {
const [items, setItems] = useState([]) // Some array with a list of items
const [sort, setSort] = useState('asc');
const sortedItems = useMemo(() => {
const copy = [...items];
copy.sort((a, b) => {
if (sort === 'asc') {
return b.name.localeCompare(a.name)
} else {
return a.name.localeCompare(b.name);
}
});
return copy;
}, [items, sort]); // <--- passing an array in the dependencies
return (
<div>
<button onClick={() => setSort(prev => prev === 'asc' ? 'dsc' : 'asc'))}>
Toggle sort
</button>
{sortedItems.map(item => (
// ...
))}
</div>
)
}
The array is the same on every render, unless someone calls setItems
to change the array. So as long as both the array and the sort stay the same, the memo will not rerun.
What would be a good refactor path to be able to use useMemo in this situation?
The general thing you need to do is make sure your object/array references do not change (or don't change often). If you'd like help with a specific situation, please share your code.