J'essaie de mettre un navigateur de pile dans un autre navigateur de pile comme celui-ci

const ProfileStack = createStackNavigator(
 {
   Profile: { screen: ProfileScreen },
   Comment: { screen: CommentStack },
 }
);

const CommentStack = createStackNavigator(
 {
   Comment: { screen: CommentScreen },
   Profile: { screen: ProfileStack },
 }
);

Puisque CommentStack est déclaré après ProfileStack, je ne peux pas réaliser ce que je veux. Y a-t-il un moyen pour que je puisse faire la même chose comme ça dans react-navigation 4?

EDIT : J'essaie de créer une application de médias sociaux et la méthode ci-dessus ne fonctionne pas. La façon actuelle je le fais de cette façon:

const ProfileStack = createStackNavigator(
 {
   Profile: { screen: ProfileScreen },
   Comment: { screen: CommentScreen },
 }
);

const CommentStack = createStackNavigator(
 {
   Comment: { screen: CommentScreen },
   Profile: { screen: ProfileStack },
 }
);

Mais quand quelqu'un accède au profil de quelqu'un et va commenter son message, puis visite le profil d'un commentateur, le natif réagit revient à l'écran du profil. Ce que je veux, c'est envoyer à une nouvelle pile de profils pour qu'elle puisse fonctionner en boucle. Désolé, l'anglais n'est pas ma langue maternelle

0
Syed Rajin 8 sept. 2020 à 12:41

1 réponse

Meilleure réponse

Comme je l'ai mentionné dans mon commentaire, vous ne pouvez pas avoir deux navigateurs qui ont l'un l'autre comme écrans. Vous pouvez avoir un navigateur qui a un autre navigateur comme écran. Mais d'après ce que j'ai compris de votre question, je ne pense pas qu'il y ait même besoin d'un ProfileStack et d'un CommentStack.

Je propose plutôt d'avoir un navigateur qui contient le CommentScreen et le ProfileScreen et de laisser vos données dicter quoi afficher et où aller. Voici un code à montrer pour illustrer ce que je veux dire:

/* 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);

Donc, l'idée ici est que vous avez un tableau qui contient les données de vos utilisateurs où chaque utilisateur est identifiable par un identifiant, userId dans cet exemple. Un utilisateur peut également avoir une propriété comments qui contient le message d'un commentateur et l'identifiant du commentateur, commenter.

En ce qui concerne la navigation, la seule chose que nous devons vraiment faire si nous avons accès à ces données et implémenter ce type de structure est de passer un userId lors de la navigation vers la page de profil et lors de la navigation vers la page de commentaires.


J'ai ajouté un MainNavigator dans cet exemple, car à partir de la question, je suppose que vous commencez à partir d'un autre écran, comme un écran d'accueil, avant de naviguer vers le profil d'un utilisateur spécifique.

Mettre à jour

OP a indiqué que le bogue de duplication d'écran avait été résolu en désactivant les boutons de navigation après les avoir appuyés. C'est certainement un moyen facile et bon de s'y prendre, mais comme cela pourrait être utile à quelqu'un, je vais également expliquer comment vous pouvez éviter la duplication dans l'état de navigation.

Duplication dans ce cas, ce qui signifie que nous avons déjà vu un itinéraire particulier et une combinaison userId. J'ai créé une fonction qui remplace les appels à push dans l'exemple précédent :

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 });
  }
}

Avec cette fonction, vous pouvez faire quelque chose comme ceci :

navigateByPushWithoutDuplicates("Comment", userId, navigation);

Et ça:

navigateByPushWithoutDuplicates("Profile", comment.commenter, navigation);
1
Bas van der Linden 11 sept. 2020 à 12:39