I have a React Native screen/component in which there is a menu button in the top-left corner of the nav/header. When that button is tapped, I want to make a menu within the screen/component itself toggle open and shut.
For whatever reason though, with how I have it set up now, the first time I tap the menu button, the menu opens, but after that, it always stays open and doesn't close, no matter how many times I tap the button. It seems like the state is not properly being updated or something.
Here's the basic code I have for the menu toggling:
const Screen = ({ navigation }) => {
const [showMenu, setShowMenu] = useState(false);
useEffect(() => {
navigation.setParams({
toggleMenu: () => {
setShowMenu(!showMenu);
}
});
}, []);
return (
<View>
{ showMenu &&
<FlatList
// Menu code here.
/>
}
{/* Other screen rendering here. */}
</View>
);
};
Screen.navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
return {
headerLeft: () => {
return (
<TouchableOpacity
onPress={params.toggleMenu}
>
<Text>Menu</Text>
</TouchableOpacity>
);
}
};
};
export default Screen;
I'm thinking that it might be some closure issue, but I'm really not sure. I added a console.log
to toggleMenu
, and the showMenu
value is always false
when I enter into the function, which then sets it to true
, thus while the menu won't close.
Why the showMenu
value is always false
, even after I use setShowMenu
to set it to true
is beyond me though. Anyone have any ideas? Thank you.
You have a stale closure in your useEffect
. Its one of the most common problems people run into with hooks. Change it to use the updater form and it should start working.
setShowMenu(prevVal => !prevVal);
showMenu
is basically stuck at it's initial value inside the useEffect
, so every time the update is called it is doing setShowMenu(!false)
. That's why it appears to work the first time.
The updater form guarantees that you will be working with the most recent copy of state.