0

I'm a newbie in React Native and struggling in cleaning up the state of the screen.

Like screen A has some states --> screen B, back to screen A, old states are clear. I'm using React Navigation V5

What I'm trying to do is:

  1. After navigating from MainMap.js to the last screen TripsListScreen.js (the whole process is a Stack of 4 screens, nested in a Drawer), I got all the data stored in Redux's store, and display it in TripsListScreen.
  2. The problem is when I press the add button in TripsListScreen to comeback at the MainMap.js, it doesn't clean up every state as I expect.

Here's the MainMap.js 's states:

const initialState = {
    hasMapPermission: false,
    _userLocationDisplayed: null,
    userLatitude: 0,
    userLongitude: 0,
    initial_UserLatitude: 0,
    initial_UserLongitude: 0,
    userLocationAddress: '',

    destination: [],
    destinationName: [],
    destinationAddress: [],
    destinationCoords: [],
    destinationImageUri: [],

    numOfInput:[0,1],
    counter: 1,
    wayPoints: [],
    markers: [],
}

class MainMap extends React.Component{

    constructor(props){
        super(props);

        this.state = initialState;


    };


    componentDidMount(){
        console.log('Hello',this.props)
        if(this.props.route.params === true){
            this.setState(initialState)
        }
        this._requestUserLocation();
    };

Basically, I tried to pass a boolean param from TripsListScreen to MainMap, and if the param is true, I'll set all the states back to the beginning. However, it doesn't work as expected.

Here's TripsListScreen:

//...
<Layout style={styles.bottom}>
      <TouchableOpacity onPress={() => props.navigation.navigate('PlanningProcess', {
            screen: 'MainMapScreen',
            params: {doAddPlace: true}
      })} style={styles.createTrip}>
          <Layout style={styles.button} >
               <Icon name='add' size={35} />
          </Layout>
      </TouchableOpacity>
</Layout>
//...

Here's the Navigation:

  1. StackNavigators:
const Stack = createStackNavigator();

const StackNavigator = (props) => {
    return(
        <Stack.Navigator screenOptions={{headerShown: false}}>
            <Stack.Screen name='MainMapScreen' component={MainMap} />
            <Stack.Screen name='TripDescription' component={TripDescription} />
            <Stack.Screen name='TripsListDetailScreen' component={TripsListDetailScreen} />
            <Stack.Screen
                name='TripsListScreen' 
                component={TripsListScreen} 
                options={{
                    headerLeft: () => (<Icon style={{marginHorizontal: 30, marginTop: 30}} color='white' name='menu' size={30} onPress={() => props.navigation.dispatch(DrawerActions.openDrawer())}/>),
                    title:'Something'
                    }}
            />
        </Stack.Navigator>
    );
};
export default StackNavigator;
  1. Main Navigators:
const Navigator = () => {

    return(
        <NavigationContainer>
            <Drawer.Navigator
                statusBarAnimation='slide'
                drawerContent={props => 
                    <DrawerContent {...props} />}>
                <Drawer.Screen name='Welcome' component={WelcomeStackScreen}  />
                <Drawer.Screen name='TripsListScreen' component={TripsListScreen} />
                <Drawer.Screen name='PlanningProcess' component={StackNavigators} />
            </Drawer.Navigator>

        </NavigationContainer>
    );
};


export default Navigator;

This is what MainMap renders:

What MainMap renders

This is what I expected, when navigating from TripsListScreen ( to create a new trip):

Expected result after cleaning

PLEASE HELP !!!

Ken Pham
  • 285
  • 6
  • 17

3 Answers3

2

ComponentDidMount in MainMap.js doesn't get triggered because the screen is mounted already. Please look at this `componentDidMount()` function is not called after navigation

  • Thanks for the help. I'm using react navigation v5. The solution in the link you provided is out of date. Can you please provide me updated guides ? – Ken Pham Mar 28 '20 at 05:10
1

in StackNavigator, screens don't unmount when you open new screens on top of them. So if you go from A to B, then from B to C, both A and B will stay mounted. If you go back from C to B, C will unmount. It's like push and pop methods on array. componentDidMount in MainMap is not being called when you go back to it, as it doesn't unmount in first place. It is explained here Navigation Lifecycle.

As you are using Redux and saying that all the data is stored in Redux store, make your MainMap component render solely from the data from store, not from own state. You can then manipulate this data from TripsListScreen by dispatching actions. The easiest would be creating something like RESET_MAIN_MAP action that will reset that part of the state for MainMap screen

Max
  • 4,473
  • 1
  • 16
  • 18
  • Hi Max. The answer is so helpful. Thank you so much. But when I mean store all the data in Redux's store, I mean after the ```MainMap``` has rendered. The```MainMap``` renders all based on its own state (polyline, search bars...). – Ken Pham Mar 28 '20 at 02:39
  • After rendering and users search places, all those places then are stored in Redux store. – Ken Pham Mar 28 '20 at 03:06
  • What I want to achieve is all the states of ```MainMap.js``` is unmounted after I navigate to it from ```TripsListScreen```. If it is the Stack Navigator the problem, can you suggest me some alternatives ? – Ken Pham Mar 28 '20 at 03:37
1

The method ComponentDidMount() only triggers for the first time at the mounting of the component and as you are navigating to a new screen, the previous screen is still mounted in the stack.

If you want to re-initialize your state every time your component gets the focus, you can set a listener on the focus on the navigation.

Like this,

const unsubscribe = navigation.addListener('willFocus', () => {
      // Do something 
      // re-initialise the state
});
Anurodh Singh
  • 814
  • 5
  • 9
  • It's amazing. Thank you so much for the help Anurodh. By the way, would you mind explaining me a bit about this thing ? So you can see on the above image, those search bars are ```PlaceInput``` class component ( ). So how can we reset all the states of that ```PlaceInput``` at the same time with doing so to ```MainMap``` ? Please guide me – Ken Pham Mar 28 '20 at 05:38
  • 1
    Welcome! If you want to reset the `` component, there are several ways to do that, 1. Connect `` component with redux and before navigating back to the Map screen dispatch an action that reset the reducer which mutates the props of that `` component and triggers the `componenDidUpdated` method, and in that method, you can reset the state of `` component. – Anurodh Singh Mar 28 '20 at 06:39
  • 1
    2. When you are navigating to the other screen, just before calling the navigate method invoke a method of `` component to reset the state of `` component. To invoke a method of the child from the parent component you have to get the reference of child component first. – Anurodh Singh Mar 28 '20 at 06:39
  • Amazing Anurodh. Thank you so so much. I just want to ask 1 more question. How can we re-mount the component after we un-mount it ? – Ken Pham Mar 28 '20 at 14:49
  • Same as you mount it the first time. If your component is in the render hierarchy(basically in return block) it will render(mount) and follow the lifecycle till the point you remove it from the render. on the basis of any condition. Whenever in future you decide to again return the same component, it will mount again. – Anurodh Singh Mar 28 '20 at 15:16
  • SO is will it remount when I navigate back to it. Since I tried to console.log in the ```componentWillMount``` and ```componentDidMount``` in ```MainMap``` but it doesn't appear. I did reset the state, but the request I made in ```componentWillMount``` ( or even ```componentDidMount```) doesn't perform when I navigate back to it ? – Ken Pham Mar 28 '20 at 15:38
  • No, I have just explained the component lifecycle but in case of navigation, when you go from `A` to `B` screen it will create a stack like `[A, B]` both are mounted one by one and when you navigate back to `A` it just navigate back to A (which is already rendered) and pop the `B` screen from the stack and now you know that `A` is already rendered (mounted) so, the `componentDidMount` methods will not invoke. However, if you deliberately want a new looking component when to navigate back from B to A you can try the `push` method(not recommended) instead of `navigate`. Same implementation. – Anurodh Singh Mar 28 '20 at 15:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/210493/discussion-between-marwin-and-anurodh-singh). – Ken Pham Mar 28 '20 at 15:58