React Native component is not triggering componentDidMount() after first mount - react-native

I have two react native components, One is profile(showing logged user details) and another one for login.
In login component I set the user details to AsyncStorage.
import {AsyncStorage} from 'react-native';
Adding user to AsyncStorage:
const user = {
fname:"Tenusha",
lname:"Guruge"
}
AsyncStorage.setItem("user",JSON.stringify(user))
In the profile component I read the AsyncStorage
componentDidMount() {
AsyncStorage.getItem("user").then(user => {
console.log(user)
this.setState({user})
})
}
When logout I clear the AsyncStorage:
AsyncStorage.removeItem("user")
Problem is Once I log in and set the user details to AsyncStorage, it store the data and I can view them in profile component. Once user logout, the data in storage are cleared, but when I navigate to profile component the previously loaded data is still there.
I need a way to read the current AsyncStorage data when every time user navigate to profile component.

To be sure a component is unmounted you can use createSwitchNavigator.
You can use a loginScreen as child while the other child is your Drawer.
When doing a logout you clear your asyncStorage and then navigate to the loginScreen and the SwitchNavigator will unmount your Drawer.
DrawerNavigation will keep the screens active while moving between his childs after every screens's first focus, making every componentDidMount getting triggered only at first render.

Track navigation changes and clear state here
Consider state-manager like redux it will be cleanest approach

Your issue is that your state is not getting cleared when using DrawerNavigator instead you can use stackNavigator if you want your component to unmount when navigating out and clearing the state automatically.
Another approach can be of using state management library such as redux or flux and clear out state whenever user is logging out.

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 clear cache from ES6 Import Module (React Native)?

I am new to React native i just build the app with two screen and using navigation like login screen and my profile screen.
I create UserData module and import this file in my profile screen. like this
import * as UserData from '../modules/UserData';
Press the logout button navigation navigate back to the login screen.
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'LoginStack' })
],
});
this.props.navigation.dispatch(resetAction);
then i login using another user id it's going to my profile screen but UserData module just still keep the Previous login user datas. How to avoid this i have no idea. Someone Please help me.
Thank you.
when logout , you must delete all the old state and props of components , StackActions.reset do not auto delete this
You can call a method on press of the logout button and in that method you need to clear the async storage and all the mobx/redux stores. After clearing the data, you navigate the user to login page and reset the navigation.

AsyncStorage not work in header if removeItem in other components

I have home.js and header.js in React.
When using this code, Information will not be erased until the simulator is refreshed
I want to clear the home page async data that state updated when navigate to home but when go to home AsyncStorage have the value
:
AsyncStorage.removeItem('mobileNumber');
this.props.navigation.navigate('Home');
Can anyone please assist me to correct this code?

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.

Accessing navigator in Actions with React-Native and Redux

Using React-Native (0.19) and Redux, I'm able to navigate from scene to scene in React Components like so:
this.props.navigator.push({
title: "Registrations",
component: RegistrationContainer
});
Additionally I'd like to be able push components to the navigator from anywhere in the app (reducers and/or actions).
Example Flow:
User fills out form and presses Submit
We dispatch the form data to an action
The action sets state that it has started to send data across the wire
The action fetches the data
When complete, action dispatches that the submission has ended
Action navigates to the new data recently created
Problems I'm seeing with my approach:
The navigator is in the props, not the state. In the reducer, I do not have access to the props
I need to pass navigator into any action that needs it.
I feel like I'm missing something slightly simple on how to access Navigator from actions without sending in as a parameter.
In my opinion the best way to handle the navigation with Redux is with react-native-router-flux, because it can delegate all the navigation logic to Redux:
You can change the route from the reducer;
You can connect the router to the store and dispatch its own actions that will inform the store about route changes (BEFORE_ROUTE, AFTER_ROUTE, AFTER_POP, BEFORE_POP, AFTER_DISMISS, BEFORE_DISMISS);
An example
Here is an example on how easily you can save the currently focused route in the store and handle it in a component (that will be aware of being focused):
1. Connect a <Route> to Redux
Connecting a <Route> to Redux is easy, instead of:
<Route name="register" component={RegisterScreen} title="Register" />
you might write:
<Route name="register" component={connect(selectFnForRegister)(RegisterScreen)} title="Register" />
You can also simply connect the component itself in its own file like you usually do.
2. Connect a <Router> to Redux
If you need to inform Redux of the navigation status (i.e. when you pop a route) just override the <Router> component included in react-native-router-flux with a connected one:
import ReactNativeRouter, { Actions, Router } from 'react-native-router-flux'
const Router = connect()(ReactNativeRouter.Router)
Now when you use a <Router> it will be connected to the store and will trigger the following actions:
Actions.BEFORE_ROUTE
Actions.AFTER_ROUTE
Actions.AFTER_POP
Actions.BEFORE_POP
Actions.AFTER_DISMISS
Actions.BEFORE_DISMISS
Take a look at this for an example.
3. Catch the interested actions in your reducer
For this example I have a global reducer (where I keep the information needed by all my app) where I set the currentRoute:
case Actions.AFTER_ROUTE:
case Actions.AFTER_POP:
return state.set('currentRoute', action.name)
Now the reducer will catch every route change and update global.currentRoute with the currently focused route.
You also can do many other interesting things from here, like saving an history of the navigation itself in an array!
4. Update your component on focus
I'm doing it on componentDidUpdate of my component of the route named payment.
If global.currentRoute is payment and the previous global.currentRoute was different, than the component has just been focused.
componentDidUpdate(prevProps) {
const prevRoute = prevProps.global.currentRoute
const currentRoute = this.props.global.currentRoute
if (currentRoute === 'payment' && prevRoute !== currentRoute) {
this.props.actions.doSomething()
}
}
P.S.: Remember to check currentRoute === 'payment', otherwise you'll start doSomething() on every route change!
Also, take a look a the README.md for learning other stuff about the integration with Redux.
Hope it helps, long live Redux!
Maybe you could pass the information about title and component in an action and the component with the navigator can then push the right scene with the information of the state.