15 votes

Comment terminer le composant actuel tout en naviguant vers le composant suivant en react native

Bonjour, je essaye de naviguer vers le prochain composant en utilisant la fonction navigate. J'utilise react-navigation pour la navigation entre plusieurs composants.

Supposons que j'ai le composant index.android.js et DashboardScreen.js. J'essaie de naviguer vers le composant DashboardScreen.js depuis le composant index.

La navigation fonctionne mais le composant index reste toujours dans la pile de composants. Lorsque je retourne en arrière, il ouvre index.android.js ce qui ne devrait pas être le cas. Est-ce que quelqu'un sait comment gérer cela dans react-native. Sur Android, finish() fonctionne pour cela.

navigate("DashboardScreen");

Lorsque je navigue de SplashScreen vers EnableNotification, alors SplashScreen devrait être détruit, si je navigue de EnableNotification vers CreateMessage, alors EnableNotification devrait être détruit et si je navigue de CreateMessage vers DashboardScreen, alors CreateMessage devrait être détruit. Pour le moment, aucun composant n'est détruit.

index.android.js

class SplashScreen extends Component {
  render() {
    if (__DEV__) {
      console.disableYellowBox = true;
    }

    const { navigate } = this.props.navigation;

    AsyncStorage.getItem("@ProductTour:key").then(value => {
      console.log(value);
      if (value) {
        navigate("DashboardScreen");
      }
    });

    return (
     ....
    );
  }
}

const App = StackNavigator(
  {
    Splash: {
      screen: SplashScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    },
    EnableNotification: {
      screen: EnableNotificationScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    },
    CreateMessage: {
      screen: CreateMessageScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    },
    DashboardScreen: {
      screen: DashboardScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    }
  },
  {
    initialRouteName: "Splash"
  }
);

7voto

Surender Kumar Points 281

Utilisez simplement 'replace' à la place de 'navigate'

this.props.navigation.replace('Nom de votre prochain composant')

4voto

GoreDefex Points 42

Tout d'abord, utiliser AsyncStorage dans une fonction asynchrone (surtout une fonction de cycle de vie) est une très mauvaise idée. Vous devriez généralement garder AsyncStorage à des endroits dans votre dossier / structure d'application qui ont du sens pour l'endroit où vous accédez / gardez les données, mais comme ce n'est pas la question, je vais juste le mentionner rapidement ici...

Essentiellement, vous demandez de naviguer une fois que la méthode ASync est complétée en fonction de CHAQUE rendu... Ceux qui sont nouveaux dans RN devraient savoir qu'un grand nombre de choses peuvent déclencher un rendu. Dans certains cas, la fonction de rendu peut se déclencher (j'ai vu cela de nombreuses fois auparavant) 10 fois ou plus avant de finaliser le dernier rendu. Cela signifie que vous auriez déclenché cette méthode ASyncStorage 10 fois... définitivement quelque chose à penser lors de la mise en œuvre de ce truc. Autrement dit, la partie .then(); de la fonction AsyncStorage se déclenche longtemps après que le rendu ait déjà fini de faire son travail. Si c'était une approche raisonnable à utiliser, je dirais de mettre la partie return de la fonction de rendu à l'intérieur de .then((value) => { return ( ... ); });. Mais c'est une idée encore pire. Fondamentalement, vous avez besoin de la bonne méthode de cycle de vie ici et ce n'est PAS la méthode de rendu.

Quoi qu'il en soit, comme je n'ai jamais utilisé cette bibliothèque de composants auparavant, je ne peux que vous orienter dans la bonne direction, alors voici... Ces documents sur leur site web semblent dire que vous avez besoin d'une référence au navigateur props passée au composant dans lequel vous l'utilisez. Donc, si vous avez créé le navigateur dans cette classe, vous utiliseriez this.refs.nomDuNavigateur.navigate('NomDeLItem'). Si vous êtes dans la classe à laquelle ce navigateur a été passé en tant que prop, vous utiliseriez this.props.nomDuNavigateurProp.navigate('NomDeLItem'). Je vois que vous utilisez la déconstruction de variables pour obtenir le rappel navigate mais je vous mettrais en garde de le faire de cette façon, car j'ai vu que cela provoque des erreurs en récupérant par erreur une ancienne version de la fonction de navigation ou sa référence parentale et provoquant un effet d'erreur en cascade.

Aussi, si vous allez utiliser AsyncStorage dans un fichier de composant (encore une fois, je recommanderais de le placer dans un composant/classe où vos données sont accédées dans toute l'application...) et que vous allez l'utiliser pour décider si l'application doit naviguer vers l'avant/vers l'arrière... assurez-vous de le supprimer de la fonction de rendu et de le mettre peut-être dans les fonctions de cycle de vie constructor, componentWillReceiveProps, componentDidReceiveProps ou componentWillUpdate. De cette façon, il se déclenche en fonction d'une mise à jour, d'un nouvel objet de propriétés passé ou une fois que le composant est construit. Tout est meilleur que de le déclencher à chaque rendu.

Enfin, je ne sais pas ce que vous avez configuré pour votre objet pile de routes StackNavigator mais vous auriez besoin d'avoir le mot-clé que vous avez utilisé "DashboardScreen" pointant vers un composant réel qui a été importé correctement. Le mot-clé "DashboardScreen" se connecterait probablement dans votre objet StackNavigator à une importation de composant comme ceci...

import Dashboard from '../Views/DashboardScreenView';

StackNavigator({
  DashboardScreen: {
    screen: Dashboard,
    path: 'dashboard/:principal',
    navigationOptions: null,
  },
});

3voto

alpha Points 867

En fonction de vos besoins, je suggère la configuration suivante :

SplashNavigator.js

const SplashNavigator = StackNavigator({
  Splash: {
    screen: SplashScreen,
    navigationOptions: {
      header: {
        visible: false
      }
    }
  }
});

AppNavigator.js

const AppNavigator = StackNavigator(
  {
    EnableNotification: {
      screen: EnableNotificationScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    },
    CreateMessage: {
      screen: CreateMessageScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    },
    Dashboard: {
      screen: DashboardScreen,
      navigationOptions: {
        header: {
          visible: false
        }
      }
    }
  },
  {
    initialRouteName: "EnableNotification"
  }
);

Dans votre index.android.js, vous rendrez le SplashNavigator.

Le SplashNavigator rendra le SplashScreen. Il a la valeur de l'état initial isReady définie sur false, donc il affichera un texte de chargement jusqu'à ce que la valeur @ProductTour:key de AsyncStorage soit chargée ( AsyncStorage est une fonction asynchrone, vous ne devriez pas la mettre dans votre fonction de rendu). Il rendra ensuite votre AppNavigator et affichera votre EnableNotification comme route initiale.

class SplashScreen extends Component {
  constructor() {
    super(props);
    this.state = {
      isReady: false,
    }
  }

  componentDidMount() {
    AsyncStorage.getItem("@ProductTour:key").then(value => {
      console.log(value);
      // vous devrez gérer le cas où `@ProductTour:key` n'existe pas
      this.setState({
        isReady: true,
      });
    });
  }

  render() {
    const { isReady } = this.state;
    return (

        {
          isReady ?

          : Chargement
        }

    );
  }
}

Ensuite, dans EnableNotificationScreen et CreateMessageScreen, modifiez votre fonction de navigation pour utiliser NavigationActions.reset à partir de doc

Exemple :

import { NavigationActions } from 'react-navigation';

handleOnPressButton = () => {
  const resetAction = NavigationActions.reset({
    index: 0,
    actions: [
      NavigationActions.navigate({ routeName: "CreateMessage" })
    ]
  });
  this.props.navigation.dispatch(resetAction);
}

3voto

truong luu Points 56

Il y a une méthode simple ici : utilisez "replace" (lien de référence repleace en navigation , Par exemple, vous êtes sur l'écran "Login" et vous voulez vous rendre à l'écran "Home", insérez ce code dans l'écran "Login"

                          { this.login() }}>

                            Cliquez pour vous connecter

et la méthode de connexion :

login(){
  this.props.navigation.replace('Home')
 }

L'écran "Login" sera remplacé par "Home" ; sur Android, appuyez sur le bouton Retour => l'application se quitte, pas d'écran précédent "Login"

1voto

Pardeep Sharma Points 31
this.props.navigation.replace('Le nom de votre prochain composant')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X