I am using react-native with react-native-navigation. I would like to reload data when a component is shown. The component is shown when a user clicks on a tab navigation button
include this as 'callIfBackToThisRoute'...
export default ( props, call ) => {
if( !props.navigation ) throw 'I need props.navigation'
const thisRoute = props.navigation.state.routeName;
props.navigation.addListener(
'willFocus',
payload => {
if( payload.state.routeName == thisRoute) call(props)
}
);
}
and use it inside your component...
componentDidMount() {
const { doIt } = this.props;
doIt()
callIfBackToThisRoute(
this.props,
(props) => doIt()
)
}
This is what I ended up using:
export default class RootNavigator extends React.Component {
state = {currentScreen: null}
_onNavigationStateChange(prevState, newState, action) {
// const currentScreen = getCurrentRouteName(currentState)
// const prevScreen = getCurrentRouteName(prevState)
// console.debug('onNavigationStateChange currentScreen=', currentScreen,
// 'prevScreen=', prevScreen, 'action.routeName=', action.routeName)
console.debug('onNavigationStateChange action.routeName=', action.routeName)
this.setState({currentScreen: action.routeName})
}
render() {
return <RootStackNavigator onNavigationStateChange={this._onNavigationStateChange.bind(this)}
screenProps={{currentScreen: this.state.currentScreen}}/>;
}
coupled with componentDidUpdate()
on the screen (which may or may not perform something depending on the screenProps's currentScreen
).
Note: I don't know what/where getCurrentRouteName()
is and it gave error for me so I don't use it and use action.routeName
directly.
See https://github.com/react-community/react-navigation/issues/2371 and https://github.com/react-community/react-navigation/issues/51#issuecomment-323536642 for more information and discussion.
For RNN v3, after trying out for quite a couple times, I finally figured out the correct way:
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
}
componentWillUnmount() {
if (this.navigationEventListener) {
this.navigationEventListener.remove();
}
}
componentDidAppear() { // Lazy loading data for RNN
if (this.state.routes.length === 0) {
this.getData();
}
}
The key is that, the binding of event listener is mandatory, otherwise the componentDidAppear() and componentDidDisappear() won't be triggered.
The currently accepted answer suggests a react-navigation solution, not react-native-navigation (RNN), so I'll go ahead and give my two cents.
As Stephen Liu points out in his answer, RNN provides screen lifecycle methods that fire when a component appears (componentDidAppear
) and disappears (componentDidDisappear
).
Stephen's answer works for a class component, however in the age of hooks I prefer function components. So this is how to use RNN's screen lifecycle methods in a function component:
import React, { useEffect } from 'react'
import { Navigation } from 'react-native-navigation'
const MyComponent = ({ componentId }) => {
useEffect(() => {
const navListener = Navigation.events().bindComponent(this, componentId)
// remove the listener during cleanup
return () => {
navListener.remove()
}
}, [componentId])
this.componentDidAppear = () => {
// do stuff when component appears
}
this. componentDidDisappear = () => {
// do stuff when component disappears
}
}
Important: MyComponent
needs a componentId
prop, which is injected automatically if it's a registered RNN screen or modal (Navigation.registerComponent
). You can also manually pass it down from a screen component to the child where you need it.
I like the solution proposed by Bruno Reis. I tweaked mine to make it a bit simpler.
class Whatever extends Component {
componentDidMount(){
this.load()
this.props.navigation.addListener('willFocus', this.load)
}
load = () => {
...
}
}
Override componentWillMount lifecycle method: https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount Or just put the functionality inside render method