I've created a menu ponent and I'm trying to use the useState hook to store which sub-menus are open. When the menu is closed (from the parent using props) I want to close all sub-menus and to do this I've using the usePrevious hook from the react-hanger library to determine when the main menu is going from OPEN > CLOSED . Here is my code.
import React, { useState } from 'react';
import { usePrevious } from "react-hanger"
const defaultMenusOpen = {menu1:false, menu2:false}
function Menu(props) {
const [subMenusOpen, setSubMenusOpen] = useState(defaultMenusOpen))
const prevIsOpen = usePrevious(props.isOpen);
if(props.isOpen === false && prevIsOpen === true){
setSubMenusOpen(defaultMenusOpen)
}
return (
{props.isOpen &&
... JSX
}
);
}
export default Menu
The problem is that this is causing an infinite loop error and continually re-rendering the Menu.
This seems to be because he if statement if TRUE on every re-render because calling setSubMenusOpen doesn't seem to cause usePrevious to store the new value again. This is what I think is happening.
- props.isOpen changes from TRUE > FALSE
- prevIsOpen and props.isOpen are TRUE and FALSE at this point, so...
- setSubMenusOpen() is called which causes a re-render.
- Instead of previsOpen and props.isOpen now being FALSE and FALSE, they remain unchanged, so setSubMenusOpen gets called again, ad finitum
Any help would be greatly appreciated.
I've created a menu ponent and I'm trying to use the useState hook to store which sub-menus are open. When the menu is closed (from the parent using props) I want to close all sub-menus and to do this I've using the usePrevious hook from the react-hanger library to determine when the main menu is going from OPEN > CLOSED . Here is my code.
import React, { useState } from 'react';
import { usePrevious } from "react-hanger"
const defaultMenusOpen = {menu1:false, menu2:false}
function Menu(props) {
const [subMenusOpen, setSubMenusOpen] = useState(defaultMenusOpen))
const prevIsOpen = usePrevious(props.isOpen);
if(props.isOpen === false && prevIsOpen === true){
setSubMenusOpen(defaultMenusOpen)
}
return (
{props.isOpen &&
... JSX
}
);
}
export default Menu
The problem is that this is causing an infinite loop error and continually re-rendering the Menu.
This seems to be because he if statement if TRUE on every re-render because calling setSubMenusOpen doesn't seem to cause usePrevious to store the new value again. This is what I think is happening.
- props.isOpen changes from TRUE > FALSE
- prevIsOpen and props.isOpen are TRUE and FALSE at this point, so...
- setSubMenusOpen() is called which causes a re-render.
- Instead of previsOpen and props.isOpen now being FALSE and FALSE, they remain unchanged, so setSubMenusOpen gets called again, ad finitum
Any help would be greatly appreciated.
Share Improve this question asked Dec 11, 2018 at 19:01 jonhobbsjonhobbs 28k39 gold badges118 silver badges179 bronze badges1 Answer
Reset to default 6Problem is that you are setting state directly in render which is causing an infinite cycle of setting state and re-rendering. Instead use the useEffect
hook and execute it only on isOpen
prop change
function Menu(props) {
const [subMenusOpen, setSubMenusOpen] = useState(defaultMenusOpen))
const prevIsOpen = usePrevious(props.isOpen);
useEffect(() => {
if(props.isOpen === false && prevIsOpen === true){
setSubMenusOpen(defaultMenusOpen)
}
}, [props.isOpen])
return (
{props.isOpen &&
... JSX
}
);
}
export default Menu