skip to Main Content

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


  1. 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.

    Login or Signup to reply.
  2. Yes, this is a bad pattern. The data is best sent as a component variable:

    <GalleryViewer imageURLs={imageURLs} />
    

    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:

    return ({imageURLs.map((url) => '<img href='+url+'>')})
    

    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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search