3

I want to not re-render my component on certain paths, trying to do this using React.memo and checking the current path using the withRouter HOC.

The compare function in React.memo does not get called.

function compare(prevProps, nextProps) {
  console.log(prevProps,nextProps)
  return (prevProps.location.pathname !== '/' && nextProps.location.pathname !== '/')
}
export default React.memo( withRouter(MyComponent), compare);
Abhiman
  • 53
  • 2
  • 7
  • 2
    From the [React docs](https://reactjs.org/docs/react-api.html#reactmemo) on `React.memo`: This method only exists as a performance optimization. Do not rely on it to “prevent” a render, as this can lead to bugs. – backtick Mar 28 '20 at 04:52
  • *Why* are you trying to prevent rerenders though? Some other underlying issue? Perhaps there's some other way to structure your components so a specific one isn't rendering unnecessarily. – Drew Reese Mar 28 '20 at 05:16
  • To optimise, I must prevent unwanted re-renders. The compare function has that specific purpose - to check if there's a need for rendering. But I can't get to invoke it. – Abhiman Mar 28 '20 at 08:48
  • You should [use the hooks](https://reacttraining.com/react-router/web/api/Hooks) in MyComponent because [withRouter](https://reacttraining.com/react-router/web/api/withRouter) does not re render unless parent re renders. – HMR Mar 28 '20 at 09:59
  • @HMR thanks for the answer. The problem to not render still remains since memo cannot access state values. – Abhiman Mar 28 '20 at 18:34
  • I guess I should be more blunt... is there some issue with extra render cycles that is compelling you to optimize `MyComponent`? I.E. are some components slow because they are remounting? Is there a component rendering a really long list? – Drew Reese Mar 28 '20 at 21:51

2 Answers2

3

just use it like this

function compare(prevProps, nextProps) {
  console.log(prevProps,nextProps)
  return (prevProps.location.pathname == nextProps.location.pathname)
}
export default withRouter(React.memo(MyComponent, compare));

Take care for the comparison you are about to do

the comparison you had has a flow, if you are in the main page where the route is / then the compare function will always return false causing re-render all the time(just like if memo didn't exist in the first place), and if your are in a sub-route other than / like /articles then the comparison will always return true causing the component to re-render al the time, just like if memo didn't exist in the first place.

What you want is a comparison that depends on new and old props having equal things which leads to save a re-render or having non-equal things which leads to a new re-render to render the fresh data for you.

So the comparison should be something like

prevProps.location.pathname == nextProps.location.pathname
Louay Al-osh
  • 3,177
  • 15
  • 28
Neo13
  • 31
  • 2
1

Thanks for your question, it was very helpful to me two months ago.

memo function take a component and a function that will be called to decide if React needs to re-render or not, if the function returns true the component will not re-render, any way if the function returns false then the props are now different and React do re-render to your component.

Now: to access the pathname correctly in the function passed to memo then memo should be wrapped with withRouter and not the opposite, withRouter wrap a component (it doesn't know it's memorized version of a component or not, it just wraps it) and pass it the routing props.

The function passed to memo as a second argument now can access the previous and new props and do the comparison as we talked earlier (where each props as inside it the fully routing details that you want).

import { memo } from 'react';

function propsAreEqualBasedOnPathname(prevProps, nextProps) {
    return prevProps.location.pathname == nextProps.location.pathname;
}

withRouter(memo(MyComponent), propsAreEqualBasedOnPathname);

Finally, take extra care for how the comparison is made inside the compare function because some mistakes might prevent your component from re-rendering in the future forever.

I found using memo with withRouter really important to improve the performance of React components, especially if the component was a page full of details and fetching logic that can cost you some time to render, so every re-render you save, increases your page performance.

Louay Al-osh
  • 3,177
  • 15
  • 28