Thanks in advance for helping with this question.
I'm working on a company's project that will restrict me from putting all the code on here, but I will try and put as much relevant code as I can without revealing state secrets.
Basically, the React Native app is using React Navigation v5 and I've been trying to figure this problem out for two days. I understand what is happening, but I don't understand why its happening or how to fix it.
Somewhere inside the app code, you have the below code.
export const Lounge = function Lounge(props: {navigation: any}) {
const {navigation: {setOptions}} = props
const bottomTabBarCtx = useContext(BottomTabBarContext)
// const [routeName, setRouteName] = useState("LoungeList")
useEffect(() => {
setOptions({tabBarVisible: bottomTabBarCtx.isVisible})
}, [bottomTabBarCtx.isVisible, setOptions])
return <Stack.Navigator initialRouteName={"LoungeList"}>
<Stack.Screen
name="LoungeList"
component={List}
options={{headerShown: false}}
/>
<Stack.Screen
name="LoungeDetails"
component={Details}
options={{
headerLeft : buttonProps => <BackButton {...buttonProps} />,
headerRight: buttonProps => <LoungeHeaderRightDetailsButton {...buttonProps} />,
headerTitle: 'Lounge Details',
}}
/>
<Stack.Screen
name="LoungeParticipants"
component={Participants}
options={{
headerLeft : buttonProps => <BackButton {...buttonProps} />,
headerRight: buttonProps => <LoungeHeaderRightDetailsButton {...buttonProps} />,
headerTitle: 'Lounge Participants',
}}
/>
<Stack.Screen
name="LoungeAdd"
component={LoungeEdit}
options={{
headerLeft : buttonProps => <BackButton {...buttonProps} />,
headerTitle: 'Create Lounge',
}}
/>
<Stack.Screen
name="LoungeEdit"
component={LoungeEdit}
options={{
headerLeft : buttonProps => <BackButton {...buttonProps} />,
headerTitle: 'Edit Lounge',
}}
/>
...
The above file simply defines the routes that can be navigated to in this section of the app.
The initial screen/route name = 'LoungeList'
That all works fine.
From the LoungeList screen, I tap on a lounge summary cell (use your imagination please), and that tap takes me to the screen underneath: LoungeDetails
Inside the LoungeDetails screen, I see the details of the lounge, and on that screen, there is also a Join Button. This button enables me to join the lounge.
The functionality is supposed to be that, when a user taps on the join button, the button goes into a loading state, and when it has finished loading, it should read Joined. This happens as it should BUT immediately after this happens I am navigated to the LoungeList screen
Below is the code I execute for joining a lounge:
const userDidJoinLounge = (joinedLounge: LoungeWithUsers) => {
if(joinedLounge){
console.log("joinedLounge before update == ", joinedLounge);
const allLoungesNew = LoungeController.replaceLoungeInLoungeArray(
userCtx.allLoungesList,
joinedLounge
);
const userLoungesNew = LoungeController.getUserJoinedLoungeArrayListOnJoin(
allLoungesNew,
userCtx.userLoungeList,
joinedLounge
);
console.log("allLounges after update == ", allLoungesNew);
console.log("joinedLounges after update == ", userLoungesNew);
userCtx.updateLoungeLists(allLoungesNew, userLoungesNew)
}
}
In the above function, the line
userCtx.updateLoungeLists(allLoungesNew, userLoungesNew)
takes in two parameters, a list of all the lounges on the app, and a list of lounges the user has joined. This function updates the context that holds these two values.
Issue: I keep getting redirected to the LoungeList screen, even though there isn't any code instructing the app to do that.
I've played around with many things and a few things that might help you in figuring out what is going on are:
It seems that the React Navigation route config is being re-rendered. I say this because when I changed the initialRouteName to be LoungeDetails, the lounge details screen (where the join button is) flickers, but it stays on the same screen. This also tells me, that at the end of that function, the stack navigator falls back to whatever initialRouteName is.
Wierdly, when I only set allLoungesNew
then the app doesn't navigate to initialRouteName
, it seems this issue only happens when I set userLoungesNew
in the userContext's state.
Thank you very much for your help. I hope I've given you enough information to solve the problem. Feel free to ask any more questions to help solve the problem. I will tell you what I am allowed to.
After about 3 days of searching the internet for an answer, the answer was pretty simple.
I had found numerous articles and suggestions telling me not to put any code for creating navigators inside the component itself.
I didnt write the original code for this app, I came on about 2 months ago, and while I had looked at the nested navigators, It didn’t immediately occur to me that the problem might be higher up the navigation chain/stack.
In the root index.tsx
file, the former developers had put the root navigator (the navigator that held all the other sub/nested navigators) inside the entry point component.
This file was the only place that any navigator was being created within the component, but I didn’t think to look there because the behaviour seemed localised to the lounge section of the app
Anyway, the fix was simple. In the root index.tsx
file, I moved every navigator declaration out of the (root) functional component, and that fixed the issue.
It was clear that the navigator was being unmourned/remounted whenever I called a state change on a state held in my UserContext, it makes sense now that because the code to create the navigators was inside a component, whenever I would change the state, the navigators would be re-rendered as well, which took me back to the initialRouteName
screen.
React Navigation v5 unlike its earlier versions now allows us to declare navigators with JSX tags, which gives us more flexibility by providing the opportunity for things like dynamic configurations of our navigators, however we have to be careful about where any/all of our navigators are declared
After 3 days on this problem, everything pointed to this solution, but I didn’t think that was the case in the code I was working on because with the exception of one file, all other navigator declarations were made outside the component.
It could be the same for you. If you’re getting that kind of behaviour when your state changes, then the problem navigator may be way up your chain of navigators.
I hope this helps someone! 😊
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With