L Becker
L Becker

Reputation: 755

Stop Rerendering Child Components When Parent State Changes in React

I have a React component, Activity, with a DataTable and a Drawer (from Material UI). I set whether the Drawer is open based on the isDrawerOpen property the Activity component's state. However, when isDrawerOpen is updated, Activity, Drawer, and DataTable all rerender.

I don't want DataTable to rerender because nothing has changed. I have tried to use React.memo and I've tried useEffect in conjunction with useRef in my DataTable functional component to not rerender if the props are the same. It's not working. How can I prevent this child component from rerendering when none of its props change?

const Activity = props => {
   const [isDrawerOpen, setIsDrawerOpen] = useState(false);
   const [tableData, setTableData] = useState(["banana", "orange", "apple"]);

   return (
      <div>
        <DataTable data={tableData} onRowClick={() => setIsDrawerOpen(true) } />
        <Drawer open={isDrawerOpen}>Some Drawer Content </Drawer>
      </div>
   )
}

Upvotes: 16

Views: 9713

Answers (1)

Ross Allen
Ross Allen

Reputation: 44880

Something actually is changing though... it's constructing a new function on each render for onRowClick, which then forces the child to re-render because it gets new props. This is what the useCallback hook is for:

const Activity = props => {
   const [isDrawerOpen, setIsDrawerOpen] = useState(false);
   const [tableData, setTableData] = useState(["banana", "orange", "apple"]);

   // Because `setIsDrawerOpen` never changes across renders, it's safe to
   // pass an empty deps array as the second argument.
   const onRowClick = useCallback(() => setIsDrawerOpen(true), []);

   return (
      <div>
        <DataTable data={tableData} onRowClick={onRowClick} />
        <Drawer open={isDrawerOpen}>Some Drawer Content </Drawer>
      </div>
   );
}

Upvotes: 12

Related Questions