How can I prevent re-render after state changed in React Hooks?
Asked Answered
F

5

16

I am trying to build an app but the problem is when I change a state, all the components re-render.

const App=()=>{
   const [showMenu,setshowMenu]=useState(false)
   

 return(
     <>

     <Header showMenu={showMenu} setShowMenu={setShowMenu}/>

     <MainArea/>

     {showMenu ? <Menu/> : null}

     <Footer/>

    </>
 )

}

When I set showMenu to true by button, a menu appears but the problem is all my components (Header,MainArea,Footer) do re-render. I don't want that. How can I solve this problem?

Feathering answered 14/11, 2021 at 17:41 Comment(0)
A
19

You can use useMemo hook.

It prevents specific jsx contents from rerendering, even when the state that those jsx contents/components use get updated.


const App=()=>{
// you can only memoize parts that do not require use of the updated variable in this case. It means that Header cannot be memoized.

const mainArea = React.useMemo( () => <MainArea/>, [] );

const footer = React.useMemo( () => <Footer/>, [] );

   const [showMenu,setShowMenu]=useState(false)
   

 return(
     <>

     <Header showMenu={showMenu} setShowMenu={setShowMenu}/>

     {mainArea}

     {showMenu ? <Menu/> : null}

     {footer}

    </>
 )

}

EDIT:

Does the really need the state of the showMenu? Or we can only pass the setShowMenu to it? If so, then you can also memoize the Header component into memo chunk like:

const header = React.useMemo( () => , [] );

Amphibious answered 14/11, 2021 at 18:54 Comment(3)
Thank you very much. That is what I was looking for. I use showMenu variable in header to set opposite of boolen value. (setShowMenu(!showMenu))Feathering
@CD, you can remove passing showMenu prop, and instead do it like setShowMenu( currValue => !currValue ) reddit.com/r/reactjs/comments/iarjb5/… Then you can memoize the <Header/> too! Cheers!Amphibious
why not use React.memo instead of useMemo?Citarella
Y
3

You can use React memo (or PureComponent if you use classes) on the components that you don't want to re-render (MainArea,Footer). This way when an update is forced by their parent they will first make a check if any of their props changed and if not (which is your case), re-render will be skipped.

However it's advisable to perform memoization on expensive components only instead of wrapping everything with React.memo, because memoization also introduces some overhead.

Yacketyyak answered 14/11, 2021 at 17:56 Comment(0)
D
1

Firstly, whenever state changes, the component re-renders. You can only make some specific components to no re-render when state change occurs using useMemo.

If you need to store information, without the information causing any re-renders, you can use useRef. Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not! You can access the current value of that ref through the ref.current property.

export default function Counter() {
  let ref = useRef(0);

  function handleClick() {
    ref.current = ref.current + 1;
    alert('You clicked ' + ref.current + ' times!');
  }

  return (
    <button onClick={handleClick}>
      Click me!
    </button>
  );
}

Clicking on the button Click me! does not trigger any re-renders, while updating the information inside the ref.

reference: https://react.dev/learn/escape-hatches

Drone answered 26/7, 2023 at 6:23 Comment(1)
In this case, the state variable is used in the render. But even if the state variable is not used there's still a re-render. Is this correct -- the update of any state variable, even if not used in the render, causes the entire page to re-render?Tush
G
0

In this case, the state is only for header component. U can bring the state inside the Header component. U can read here for further explaination https://overreacted.io/before-you-memo/

Also here another good explanation How to prevent re-rendering of components that have not changed?

Gorden answered 1/9, 2022 at 16:4 Comment(0)
S
-3

To prevent re-rendering of reusable component while changing other states, We can use React.memo()

const MainArea = React.useMemo(() => {
return <div />;
});
const Footer = React.useMemo(() => {
   return <div />;
});
const App = () => {
   const [showMenu,setshowMenu]=useState(false)

   return(
      <>
      <Header showMenu={showMenu} setShowMenu={setShowMenu}/>
      <MainArea/>
      {showMenu ? <Menu/> : null}
      <Footer/>
      </>
  )
}
Scrimmage answered 31/5, 2022 at 8:15 Comment(1)
Mila said that already; over a year ago.Dilapidate

© 2022 - 2024 — McMap. All rights reserved.