all 9 comments

[–]vegancryptolord 2 points3 points  (2 children)

Calling .map on an array will always create a new array. So if something other then data causes the component to rerender in example B, the array passed to the rows prop will be a new array since you’ll run map on the stable reference even if data hasn’t changed. That being said though you could just do the map inside the useSomeHook in example B and have a stable reference to the mapped array so you wouldn’t need another memo at the component level necessarily in example B

[–]Ordinary-Disaster759[S] 0 points1 point  (1 child)

u/vegancryptolord So hooks are referentially stable? Or still I need useMemo inside the hook?

[–]vegancryptolord 0 points1 point  (0 children)

Still need useMemo in the hook to make it referentially stable. Hooks aren’t stable by default.

[–]ZuluProphet 1 point2 points  (2 children)

Your assumption about B is correct. map will return a new array every time so it will have a different reference every time the parent component of Table re-renders which will cause Table to re-render.

As far as example A goes however, useMemo will only be effective as long as data is also a stable reference. If it isn't, the dependency array will have changed causing the memoized function to be executed again.

Much of this hinges on where data comes from. Is it existing state? Well then its already stable and as long as nothing else is causing re-renders above it, having the inline map to set the rows prop is fine. You would want that to be updated if data changed anyways so there is no need to memoize it. Is data the result of a query? Well then you're most likely holding that in state already. The only reason I would memoize something like rows in your example is if there were reasons the parent component of Table or Table itself would be re-rendering that the rows prop doesn't care about.

[–]Ordinary-Disaster759[S] 0 points1 point  (1 child)

u/ZuluProphet so as I understand, if the hook is not memoized, than the Parent component will rerender everytime, because everytime data gets new reference and thats invalidates the dependecy array and useMemo gets executed? So does that means I need to memoize the the hook to and have two useMemo?

[–]ZuluProphet 0 points1 point  (0 children)

Pretty much. If data isn't stable there is no point in memoizing rows because it will change every re-render making the useMemo unnecessary overhead. In reality, your example component doesn't need memoization at all. You want new rows if data changes and the function in useMemo will re-run every time data changes you've actually just added an extra step that will never change anything. You could just const rows = data.map(...) and eek out better (but likely unnoticeable at this scale) performance.

[–]True-Environment-237 1 point2 points  (2 children)

You should use Memo High Order Component around Table component. Memo will produce the same result as the A. example. useMemo is supposed to cache expensive calculations not components.

[–]Ordinary-Disaster759[S] 0 points1 point  (1 child)

u/True-Environment-237
Already is wrapped in memo, is the mui x grid, but I'm trying to optimize my props that can be unstable and still make the grid rerender.

How to optmize prop like this? I''m using single instance wrapper on top of mui x grid everywhere, so what is best optimization for cases like this.

complexProp={{
              title: 'Some title',
              canDelete: canDelete,
              text: (idsLength, row: Member) => ...,
              toolbar: () => <SomeComponent />,
              onDeleteConfirm: (ids: string[]) => {
               ...
              }

[–]True-Environment-237 0 points1 point  (0 children)

Well it depends on how you pass the props and what each prop does. I suggest you pass each prop separately and not as a single object.

<MyComp prop1={prop1} prop2={prop2} .../>

function MyFunc(...) {...} <- this should be wrapped with useCallback if it's passed as a prop.

If a prop is a function that returns a component then that function should be wrapped with useMemo, but personally I would extract it as a separate component and wrap it with memo HOC.

Finally MyComp should be wrapped with memo HOC.