For example, if I have the main component and it uses a useEffect()
to fetch data from the server, and then uses a GalleyViewer
to display the images in a 3 x 3 grid and it can allow the user to go to next page and prev page.
So I would do a:
<GalleryViewer
imageURLs={data.items.map(e => e.details.url)}
...
/>
However, since every re-render, this map()
is going to be run once.
Is it true that if the loop is, say, merely 50, then it is not a big concern. But what if it is a big number, such as 500 or 1000, then it may not be so ideal.
Also, since map()
creates a new array each time, that means GalleryViewer
will be re-rendered also, even though it doesn’t need to.
But what if I don’t feel any sluggish UI at all on my local development machine? Is it a best practice to optimize it? What if on my MacBook Air M2, it feels fast, but what about some users who may be using a 4 year old low end PC that the tech department gave them at work?
I can think of using useEffect()
to set a state imageURLs
whenever the data
changes:
useEffect(() => {
setImageURLs(data.items.map(e => e.details.url))
},
[data]
);
or use a useMemo
to cache an imageURLs
, but these also seem to increase the coupling of the code: to use GalleryViewer
, the useEffect
is needed, and the programmer need to constantly monitor if the dependency array needs to be modified due to some other parts of the code being changed.
Another way if we can refactor GalleryViewer
:
const urlSelector = useCallback(
e => e.details.url,
[]
);
return ( ...
<GalleryViewer
items={data.items}
urlSelector={urlSelector}
...
/>
so if data.items
doesn’t change, there is no re-rendering of GalleryViewer
. The urlSelector
function is run only for 9 times for that 3 x 3 grid, so it won’t be going through the whole array.
Come to think about it, if Redux is being used, then since Redux would construct a new value every time (so that it is immutable), that means data
will be a new value and it will cause the useEffect
or useMemo
to run, so it doesn’t help in this case?
So is using map()
in the original code an antipattern in React and what is a best practice?
2
Answers
My gut feeling is it’s fine. Even for large arrays you would probably feel the performance issue somewhere else (like when you’re fetching the data) before you would have an issue because of the map.
React does the work to handle this on the virtual DOM (and avoids making unnecessary changes to the DOM), so I don’t think it will amount to much of a performance hit.
I would say move forward with the first way you have written it and refactor later if you have a problem.
Yes, this is a bad pattern. The data is best sent as a component variable:
This variable is taken from redux and when it is updated the component is re-rendered. We don’t even need useEffect , we just output data:
And this will be the best solution. It is necessary to follow the principle of SOLID architecture, if you do not know, you need to read about it