Harrison Cramer
Harrison Cramer

Reputation: 4496

Prevent Re-Render With Modifications to Parent State

How can one modify state in a parent component, and pass it down as props to the children, but only re-render those children when the modified state changes?

My basic setup currently works, but it's causing some unnecessary re-renders. The parent components gets information from the URL (using react-router hooks) and modifies it, and then passes that down as props to its children. The component looks like this:

 const myComponent = () => {

    const { dataType } = useParams();
    const { search } = useLocation();

    /// These functions help me transform that data into something more manageable
    const y = queryString.parse(search).collection;
    const { collections, gqlQuery } = getCollections(dataType);
    const collection = collections.find(x => x.value === y);

    return (
     <MyChild collection={collection} /> ... This component is re-rendering unnecessarily.
    )



};

How can I ensure that when the URL doesn't change (the dataType and search values that are pulled using react-router) the child components that receive derived data ALSO won't unnecessarily re-render?

Upvotes: 0

Views: 774

Answers (1)

Agney
Agney

Reputation: 19204

The first step would be to make sure that the reference to collection variable changes only when one of the dependencies change:

useMemo(() => {
  const y = queryString.parse(search).collection;
  const { collections, gqlQuery } = getCollections(dataType);
  const collection = collections.find(x => x.value === y);
}, [search, dataType]);

The second would be to make sure that the component only re-renders when it receives new props:

import { memo } from 'react';

function Child() {

}

export default memo(Child);

You can also use the second argument for memo to customise what is compared.

function Child(props) {

}
function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}
export default React.memo(Child, areEqual);

React.memo - Docs React.useMemo - Docs

PS: Note that React is usually super fast with re-renders. Use these only as a performance enhancement after measuring their impact. There is a chance it has worse performance than before

Upvotes: 1

Related Questions