Reputation: 223
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?
Upvotes: 18
Views: 53386
Reputation: 51
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
Upvotes: 1
Reputation: 525
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?
Upvotes: 1
Reputation: 255
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/>
</>
)
}
Upvotes: -3
Reputation: 569
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}
</>
)
}
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( () => , [] );
Upvotes: 22
Reputation: 1065
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.
Upvotes: 3