Reputation: 71
I am trying to put a stack navigator inside another stack navigator like this
const ProfileStack = createStackNavigator(
{
Profile: { screen: ProfileScreen },
Comment: { screen: CommentStack },
}
);
const CommentStack = createStackNavigator(
{
Comment: { screen: CommentScreen },
Profile: { screen: ProfileStack },
}
);
since CommentStack is declared after ProfileStack I am not able to achieve what I want. Is there any way I can do the same thing like this in react-navigation 4?
EDIT: I am trying to make a social media app and the above way doesn't work. The current way I am doing it in this way:
const ProfileStack = createStackNavigator(
{
Profile: { screen: ProfileScreen },
Comment: { screen: CommentScreen },
}
);
const CommentStack = createStackNavigator(
{
Comment: { screen: CommentScreen },
Profile: { screen: ProfileStack },
}
);
But when someone goes to someone's profile and goes to comment on his/her post then visits a profile of a commenter react-native navigates back to the profile screen. What I want is to send to a new profile stack so it can work in a loop. Sorry English is not my first language
Upvotes: 0
Views: 696
Reputation: 15462
Like I mentioned in my comment you can't have two navigators that have each other as screens. You can have one navigator that has another navigator as a screen. But from what I understand from your question I don't think there is even a need for a ProfileStack
and a CommentStack
.
I propose instead to have one navigator that holds the CommentScreen
and the ProfileScreen
and to let your data dictate what to show and where to go. Here is some code to show to illustrate what I mean:
/* The users in your system identified by an id
and the comments they have on their profile */
const profileData = [
{
userId: 1,
comments: [
{ message: 'message from 2', commenter: 2 },
{ message: 'message from 3', commenter: 3 },
],
},
{
userId: 2,
comments: [{ message: 'message from 1', commenter: 1 }],
},
{
userId: 3,
comments: [{ message: 'message from 2', commenter: 2 }],
},
];
/* A simple profile screens that displays a user's profile
and that has a button to navigate to the comment page. */
const ProfileScreen = ({ navigation }) => {
const userId = navigation.getParam('userId');
return (
<View>
<Text>{`Profile of user ${userId}`}</Text>
<Button
title="go to comments"
onPress={() => {
navigation.push('Comment', { userId });
}}
/>
</View>
);
};
/* The comment screen shows all the comments a user has
and displays a button next to a comment to go to that
commenter's profile */
const CommentScreen = ({ navigation }) => {
const userId = navigation.getParam('userId');
return (
<View>
<Text>{`Comments of user ${userId}`}</Text>
{profileData
.filter((user) => user.userId == userId)[0]
.comments.map((comment) => {
return (
<View style={{ flexDirection: 'row' }}>
<Text>{comment.message}</Text>
<Button
title={`Go to ${comment.commenter}'s Profile'`}
onPress={() =>
navigation.push('Profile', { userId: comment.commenter })
}
/>
</View>
);
})}
</View>
);
};
// The screen you use to navigate to the profile screen
const InitialScreen = ({ navigation }) => {
return (
<View>
<Text>{`InitialScreen`}</Text>
<Button
title="Go to profile 1"
onPress={() =>
navigation.navigate('Profile', {
userId: 1,
})
}
/>
</View>
);
};
const ExampleNavigator = createStackNavigator({
Profile: { screen: ProfileScreen },
Comment: { screen: CommentScreen },
});
const MainNavigator = createStackNavigator(
{
SomeInitialScreen: { screen: InitialScreen },
ExampleNavigator: { screen: ExampleNavigator },
},
{
headerMode: 'none',
}
);
export default createAppContainer(MainNavigator);
So the idea here is that you have an array that holds the data of your users where each user is identifiable by an id, userId
in this example. A user could also have a comments
property that holds the message
from a commenter and the commenter's id, commenter
.
As far as navigation goes the only thing we really have to do if we have access to this data an implement this kind of structure is to pass a userId
when navigating to the profile page and when navigating to the comment page.
I have added a MainNavigator
in this example, because from the question I presumed you start from another screen, like a home screen, before you navigate to a specific user's profile.
Update
OP has indicated that the duplicating screen bug was solved by disabling the navigation buttons after pressing them. This is definitely an easy and good way to go about it, but since it might be helpful to someone I'll also explain how you could go about preventing duplication in the navigation state.
Duplication in this case meaning that we've already seen a particular route and userId
combination. I've created a function that replaces the calls to push in the previous example:
function navigateByPushWithoutDuplicates(routeName, userId, navigation) {
const screenNavigatedToBefore = navigation
.dangerouslyGetParent()
.state.routes.find(
(element) =>
element.params.userId === userId && element.routeName === routeName
);
if (screenNavigatedToBefore !== undefined) {
const navigateAction = NavigationActions.navigate({
routeName: routeName,
params: { userId: userId },
key: screenNavigatedToBefore.key,
});
navigation.dispatch(navigateAction);
} else {
navigation.push(routeName, { userId: userId });
}
}
With this function you could do something like this:
navigateByPushWithoutDuplicates("Comment", userId, navigation);
and this:
navigateByPushWithoutDuplicates("Profile", comment.commenter, navigation);
Upvotes: 1