React Navigation v4 lifecycle events do not fire when navigating to the same screen - react-native

Let's say I have a ProductScreen component that renders info about a product as well as a list of other similar products. When clicking on a similar product, a navigation is done from ProductScreen ==> ProductScreen with different params/key.
The problem I'm facing is that I want to do something on the React Navigation focus event (for example, scroll to top)
navigation.addListener('didFocus', () => {
console.log('didFocus')
scrollToTop()
})
I see the log the first time the component renders, but when doing a navigation from ProductScreen ==> ProductScreen, the didFocus event doesn't seem to be firing again so the component isn't scrolled to the top. In fact, none of the lifecycle events (willFocus, didFocus, willBlur, didBlur) seem to be firing.
Is there any way to be able to use react navigation lifecycle events when navigating from component X to component X with different params? Thanks!

You're navigating to the same screen so it's normal that didFocus doesn't fire, since the screen was already focused.
If you want to react to params change, you can use componentDidUpdate/useEffect to compare previous params with the new params and do what you need to do.
If you want to navigate to a new screen, you can use push instead of navigate

Related

Why does my state persist on screen change?

I am developing a React Native app and I am currently using a component in 2 different places of my app. I navigate from one place to another using a Drawer Navigator (React Navigation v6). This component updates a state when receiving a response from an API. However, if I switch to the other place where this component gets rendered, the state remains (therefore the visual message from the API appears inside it).
Why does this happen? Shouldn't all states reset on unmount and get the initial value (the one passed to useState()) when the component gets mounted again? This not the behavior I want and from what I know, this was not supposed to happen.
What can I do to make my state not persist on screen change? I have implemented the code below to be executed when a menu screen is selected, but has no effect on this issue:
navigation.dispatch(
CommonActions.reset({
index: 0,
key: null,
routes: [{ name: targetScreen }]
})
This behavior in react-native differs from react. This is documented here.
If you are coming to react-navigation from a web background, you may assume that when user navigates from route A to route B, A will unmount (its componentWillUnmount is called) and A will mount again when user comes back to it. While these React lifecycle methods are still valid and are used in react-navigation, their usage differs from the web.
Consider a screen A and a screen B. Suppose we navigate from A to B.
When going back from B to A, componentWillUnmount of B is called, but componentDidMount of A is not because A remained mounted the whole time.
This is valid for all navigators in react-native-navigation. Thus, if we have a tab bar navigation with 5 tabs, and each tab nests a Stack, then we could navigate on one stack to a certain depth, then switch the tab, and then switch the tab back again, and all screens visited will remain mounted.
Edit: In response to the comments. The recommended standard pattern to resolve your issue is as follows.
// some state in my component
const [state, setState] = useState()
useFocusEffect(
React.useCallback(() => {
// set state to initial value
setState()
}, [])
);
This is described here.
Your component does not unmount when you navigate out of component. Consider manually reseting your state inside this hook useFocusEffect

How to refresh a component which is already present in stack after navigating from another component in react native

Ex- I have two components A and B. I need to refresh component A after navigating from component B.
componentDid Mount doesn't work because A is already mounted.
How to achieve this. I am using react navigation to navigate from B->A
You can either use NavigationEvents from react-navigation or can pass a callback which will trigger on navigation.goBack().
Check this snack : Temporary Link
You can add a listener for the same in react native.
There are total 4 listners for the same.
willFocus - the screen will focus
didFocus - the screen focused (if there was a transition, the transition completed)
willBlur - the screen will be unfocused
didBlur - the screen unfocused (if there was a transition, the transition completed)
Try the below code
componentDidMount(){
const didFocusSubscription = this.props.navigation.addListener(
'didFocus',
payload => {
console.warn('didFocus ', payload);
# just write your code/call a method here which you want to execute when the app comes from a component
this.handleRefresh()
}
);
}
Dont forget to remove it when it is done.
componentWillMount(){
didFocusSubscription.remove();
}
More you can read here. Thanks :)

React Native - AppState 'change' event get no call when navigating between screens

AppState.addEventListener('change', ...)
The listener does not getting any call. I'm using StackNavigator to put root screen and the screen with AppState
(Updated) It's been called when I restart the app. But the Component where I use AppState is not yet the active screen
In my case, I just want to get notified when a navigation come back to or leave a screen. So I can simply do this
this.props.navigation.addListener('didFocus', ...);
this.props.navigation.addListener('didBlur', ...);
The problem with AppState still remains

React-native componentWillMount not calling

I am new in react-native I have two screens in my stack. Login and Home.
I want to go back to login from a button on home.
I am writing this code
this.props.navigation.navigate('loginScreen')
but in login screen componentWillMount method is not calling. I want to reset my form when user come on login screen from home.
Can anyone help me here?
Thanks in advance.
The this.props.navigation.navigate('loginScreen') don't work because you are now in loginScreen.
If you want to restart page this code isn't good. because have a loop!
correct code:
just when navigate to loginScreen from home use:
this.props.navigation.push('loginScreen')
NOT IN "componentWillMount"
To go back from login from home , you should use this.props.navigation.goBack() if the screen is immidiately before home.
Secondly, you should not use componentWillMount since it is deprecated and will be removed from React 17 onwards. Instead use componentDidMount
Since the component is already mounted therefore it won't call the react lifecycle events componentDidMount again. Therefore you should use the react-navigation listeners didFocus event.
didFocus: the screen focused (if there was a transition, the transition completed)
componentDidMount () {
this._onFocusListener = this.props.navigation.addListener('didFocus', (payload) => {
// Perform the reset action here
});
}
Since your Home and Login Screens are both under the same StackNavigator, when you go from Home back to Login the state stays the same as the component doesn't unmount. The recommended way to solve this is using the SwitchNavigator of react-navigation. Read this very helpful part of the documentation below
https://reactnavigation.org/docs/en/auth-flow.html
You may not be familiar with SwitchNavigator yet. The purpose of
SwitchNavigator is to only ever show one screen at a time. By default,
it does not handle back actions and it resets routes to their default
state when you switch away.
The perfect solution is with this.props.navigation.push('Login'), I tried with SwitchNavigator but it doesn't provide navigationOptions for header.

React Native Router Flux Drawer

I am trying to change the state of my app when the drawer is opened.
onEnter and onOpen don't trigger at all.
I am using a custom NavBar so the hamburger button isn't being displayed but if i swipe left on my IOS device the drawer opens.
So how can i detect when the drawer is open?
You have multiple choices!
Pass this.props.open and check this on componentWillReceiveProps and after that :
Actions.refresh({key: "drawer", open: true})
Same issue is here
Some more data that is good for your problem here
Drawer in router flux provided by React Navigation so it's better that you see this documentation
react native router flux drawer added in v4 so maybe have a some bug now!
Use another drawer (I recommended to you this)