web-dev-qa-db-fra.com

Comment terminer le composant en cours lors de la navigation vers le composant suivant dans réagit natif

Bonjour, j'essaie de naviguer jusqu'au composant suivant à l'aide de la fonction navigate. J'utilise react-navigation pour la navigation entre plusieurs composants.

Supposons que j'ai index.Android.js et DashboardScreen.js composant. J'essaie de naviguer vers le composant DashboardScreen.js à partir du composant d'index. 

Il navigue mais le composant d'index est toujours conservé dans la pile de composants. Quand j'appuie en arrière, il ouvre index.Android.js qui ne devrait pas l'être. Est-ce que quelqu'un sait comment gérer cela dans react-native. Dans Android, finish() fonctionne pour cela.

navigate("DashboardScreen");

Lorsque je navigue de SplashScreen à EnableNotification alors SplashScreen devrait être détruit, si je navigais de EnableNotification à CreateMessage alors EnableNotification devrait être détruit et si je naviguais de CreateMessage à DashboardScreen puis CreateMessage devrait être détruit. Pour l'instant, aucun composant n'est en cours de destruction.

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"
  }
);
14
N Sharma

Tout d’abord, utiliser AsyncStorage dans une fonction synchrone (en particulier celle du cycle de vie) est une si mauvaise idée. Vous devez généralement conserver ASyncStorage dans des emplacements de votre structure de dossier/application qui soient parfaitement adaptés à l'endroit où vous accédez/conservez des données, mais comme ce n'est pas la question, je vais simplement le mentionner rapidement ici ...

Fondamentalement, vous demandez de naviguer une fois que la méthode ASync s’est complétée en fonction de CHAQUE rendu ... Les nouveaux venus chez RN devraient savoir que beaucoup de choses peuvent provoquer un rendu. Dans certains cas, la fonction de rendu peut se déclencher (je l’ai déjà vu plusieurs fois auparavant) au moins 10 fois avant de finaliser le dernier rendu. Cela signifie que vous auriez tiré cette méthode ASyncStorage 10 fois ... certainement quelque chose à penser lors de la mise en œuvre de ce genre de choses. Donc plus ou moins, la partie .then(); de la fonction AsyncStorage est lancée longtemps après que le rendu a 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 la .then((value) => { return ( ... ); });. Mais c'est une idée encore pire. En gros, 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 aider à vous orienter dans la bonne direction, alors voilà ... Ces documents sur leur page Web semblent indiquer qu'il vous faut une référence au navigateur d'accessoires transmis au composant dans lequel vous l'utilisez. Donc, si vous avez créé le navigateur dans cette classe, vous utiliseriez this.refs.whateverYouNamedTheNavigatorReference.navigate('SomeItemName'). Si vous êtes dans la classe à laquelle ce navigateur a été transmis comme accessoire, vous utilisez this.props.passNavigatorPropName.navigate('SomeItemName'). Je vois que vous utilisez une déconstruction variable pour obtenir le callback navigate, mais je vous le déconseille, car je l'ai vu provoquer des erreurs en récupérant une ancienne version de la fonction de navigation ou de sa référence parente et en provoquant un effet d'erreur en cascade. .

De plus, si vous allez utiliser ASyncStorage dans un fichier de composant (encore une fois, nous vous recommandons de le placer dans un composant/une classe où vos données sont accessibles via l'application ...) et que vous allez l'utiliser pour décider si l'application doit naviguer en avant/en arrière ... le supprimer définitivement de la fonction de rendu et le placer 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 obj transmis ou d'une fois lors de la construction du composant. Tout vaut mieux que de le lancer à chaque rendu.

Enfin, je ne sais pas ce que vous avez configuré pour votre objet de pile de route StackNavigator, mais vous auriez besoin que le mot-clé que vous avez utilisé "DashboardScreen" pointe 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 telle que so ...

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

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

En fonction de vos besoins, je suggère de suivre 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 la SplashNavigator.

La SplashNavigator rendra la SplashScreen. La valeur d'état initiale isReady étant définie sur false, le texte de chargement sera restitué jusqu'à ce que la valeur @ProductTour:key de AsyncStorage soit chargée (AsyncStorage est une fonction asynchrone, vous ne devriez pas le placer dans votre fonction de rendu). Il rendra ensuite votre AppNavigator et 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);
      // you will need to handle case when `@ProductTour:key` is not exists
      this.setState({
        isReady: true,
      });
    });
  }

  render() {
    const { isReady } = this.state;
    return (
      <View style={{flex: 1}}>
        {
          isReady ?
          <AppNavigator />
          : <Text>Loading</Text>
        }
      </View>
    );
  }
}

Puis, sur EnableNotificationScreen et CreateMessageScreen, modifiez votre fonction de navigation pour utiliser NavigationActions.reset 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);
}
3
alpha

Oui, en mode natif, vous pouvez terminer l'écran actuel avant de naviguer vers le nouvel écran à l'aide de NavigationActions. S'il vous plaît se référer ce lien -

http://androidseekho.com/others/reactnative/finish-current-screen-on-navigating-another-in-react-native/

0
priyanka

Il existe un moyen simple ici: utilisez "replace" (lien de référence repleace dans la navigation , par exemple, vous êtes à l’écran "Connexion", Et vous voulez aller à l’écran "Accueil", code dans l'écran "Login"

                         <TouchableOpacity onPress={() => { this.login() }}>

                            <Text}>Click me to Login</Text>

                        </TouchableOpacity>

et méthode login: 

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

Écran "Connexion" sera remplacé par "Accueil", dans Android, appuyez sur le bouton Précédent => sortie de l'application, pas d'écran arrière "Connexion"

0
truong luu

SplashNavigator.js

const SplashNavigator = StackNavigator({
  Splash: {
    screen: SplashScreen,
    navigationOptions: {
      header: null}
    }
  }
});
0
Danish Hussain