J'utilise stackNavigator
pour naviguer entre les écrans. J'appelle deux API dans la fonction componentDidMount()
dans ma deuxième activité. Lorsque je le charge pour la première fois, il est chargé avec succès. Ensuite, j'appuie sur le bouton de retour pour revenir à la première activité. Ensuite, si je vais à nouveau à la deuxième activité, les API ne sont pas appelées et j'obtiens une erreur de rendu. Je ne trouve aucune solution à cela. Toute suggestion serait appréciée.
Si quelqu'un vient ici en 2019, essayez ceci:
import {NavigationEvents} from 'react-navigation';
Ajoutez le composant à votre rendu:
<NavigationEvents onDidFocus={() => console.log('I am triggered')} />
Désormais, cet événement onDidFocus sera déclenché à chaque fois que la page se concentrera bien qu'elle provienne de goBack () ou de la navigation.
Si la syntaxe votée qui utilise le composant NavigationEvents ne fonctionne pas, vous pouvez essayer avec ceci:
// no need to import anything more
// define a separate function to get triggered on focus
onFocusFunction = () => {
// do some stuff on every screen focus
}
// add a focus listener onDidMount
async componentDidMount () {
this.focusListener = this.props.navigation.addListener('didFocus', () => {
this.onFocusFunction()
})
}
// and don't forget to remove the listener
componentWillUnmount () {
this.focusListener.remove()
}
React-navigation maintient le composant monté même si vous naviguez entre les écrans. Vous pouvez utiliser le composant pour réagir à ces événements:
<NavigationEvents
onDidFocus={() => console.log('hello world')}
/>
Plus d'informations sur ce composant ici .
La documentation React-navigation décrit explicitement ce cas :
Considérons un navigateur de pile avec les écrans A et B. Après avoir navigué vers A, son componentDidMount est appelé. En poussant B, son componentDidMount est également appelé, mais A reste monté sur la pile et son componentWillUnmount n'est donc pas appelé.
En revenant de B à A, componentWillUnmount de B est appelé, mais componentDidMount de A n'est pas parce que A est resté monté tout le temps.
Il y a maintenant 3 solutions pour cela:
Abonnement aux événements du cycle de vie
...
React Navigation émet des événements pour filtrer les composants qui s'y abonnent. Vous pouvez vous abonner à quatre événements différents:
willFocus
,willBlur
,didFocus
etdidBlur
. En savoir plus à leur sujet dans la référence API.Beaucoup de vos cas d'utilisation peuvent être couverts par le composant
withNavigationFocus
d'ordre supérieur, le composant<NavigationEvents />
Ou le crochetuseFocusState
.
withNavigationFocus
composant d'ordre supérieur<NavigationEvents />
withNavigationFocus
composant d'ordre supérieur
import React from 'react';
import { Text } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
class FocusStateLabel extends React.Component {
render() {
return <Text>{this.props.isFocused ? 'Focused' : 'Not focused'}</Text>;
}
}
// withNavigationFocus returns a component that wraps FocusStateLabel and passes
// in the navigation prop
export default withNavigationFocus(FocusStateLabel);
Composant <NavigationEvents />
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const MyScreen = () => (
<View>
<NavigationEvents
onWillFocus={payload => console.log('will focus', payload)}
onDidFocus={payload => console.log('did focus', payload)}
onWillBlur={payload => console.log('will blur', payload)}
onDidBlur={payload => console.log('did blur', payload)}
/>
{/*
Your view code
*/}
</View>
);
export default MyScreen;
useFocusState hook
Installez d'abord la bibliothèque yarn add react-navigation-hooks
import { useNavigation, useNavigationParam, ... } from 'react-navigation-hooks'
function MyScreen() { const focusState = useFocusState(); return <Text>{focusState.isFocused ? 'Focused' : 'Not Focused'}</Text>; }
Voici ma solution personnelle, en utilisant onDidFocus()
et onWillFocus()
pour effectuer le rendu uniquement lorsque les données ont été extraites de votre API:
import React, { PureComponent } from "react";
import { View } from "react-native";
import { NavigationEvents } from "react-navigation";
class MyScreen extends PureComponent {
state = {
loading: true
};
componentDidMount() {
this._doApiCall();
}
_doApiCall = () => {
myApiCall().then(() => {
/* Do whatever you need */
}).finally(() => this.setState({loading: false}));
};
render() {
return (
<View>
<NavigationEvents
onDidFocus={this._doApiCall}
onWillFocus={() => this.setState({loading: true})}
/>
{!this.state.loading && /*
Your view code
*/}
</View>
);
}
}
export default MyScreen;
Dans React, componentDidMount n'est appelé que lorsque le composant est monté. Je pense que ce que vous essayez de faire est d'appeler votre API lors du retour dans StackNavigator. Vous pouvez passer une fonction de rappel comme paramètre lorsque vous appelez naviguer comme ceci sur l'écran parent:
navigate("Screen", {
onNavigateBack: this.handleOnNavigateBack
});
handleOnNavigateBack = () => {//do something};
Et sur l'écran enfant
this.props.navigation.state.params.onNavigateBack();
this.props.navigation.goBack();
Vous souhaitez effectuer quelque chose après chaque navigation vers un composant à l'aide de drawernavigator
ou stacknavigator
; à cet effet, NavigationEvents
convient mieux que componentDidMount
.
import {NavigationEvents} from "react-navigation";
<NavigationEvents onDidFocus={()=>alert("Hello, I'm focused!")} />
Remarque : si vous souhaitez effectuer la tâche à chaque fois après vous être concentré sur un composant à l'aide de la navigation dans les tiroirs ou de la navigation dans la pile, puis à l'aide de NavigationEvents
est une meilleure idée. Mais si vous souhaitez effectuer la tâche une fois, vous devez utiliser componenetDidMount
.