react-navigation from 1.x to 5, how to migrate redux actions

Viewed 586

App has all old code which I am upgrading to latest versions. It was using Redux for state management with StackNavigator. Since that is not supported, I am not able to understand how to migrate my existing redux actions, which were changing screens on various events. An example action:

export const goToHome = () => ({
  type: PUSH,
  routeName: 'projectList',
});

Which earlier reached navReducer, which handled POPing and PUSHing of screens.

export default (state = initialState, action) => {
  let nextState;
  switch (action.type) {
    case NAV_POP:
      nextState = AppNavigator.router.getStateForAction(
        NavigationActions.goBack(),
        state
      );
      break;
    ...

Please suggest. Thanks.

2 Answers

you can navigate through navigation container ref

you can call navigation().navigate("Settings") or navigation().goBack() in reducer

here is the demo of export navigation: https://snack.expo.io/@nomi9995/2eb7fd

App.js

import React,{useEffect} from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const navRef = React.createRef();

export const navigation=()=>{
  return navRef.current && navRef.current
}

const TestComponent=()=> {
  useEffect(()=>{
    setTimeout(() => {
      navigation().navigate("Settings")
      setTimeout(() => {
        navigation().goBack()
      }, 3000);
    }, 100);
  })
  return (
    <View style={styles.container}>
      <Text>TestComponent 1</Text>
    </View>
  );
}


const TestComponent2=()=> {
  return (
    <View style={styles.container}>
      <Text>TestComponent 2</Text>
    </View>
  );
}


const RootStack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer ref={navRef}>
      <RootStack.Navigator>
        <RootStack.Screen name="Home" component={TestComponent} />
        <RootStack.Screen name="Settings" component={TestComponent2} />
      </RootStack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

reducder.js

import { navigation } from 'path of App.js';

export default (state = initialState, action) => {
  let nextState;
  switch (action.type) {
    case NAV_POP:
      nextState = navigation().goBack()
      break;

The navigationRef is used for the scenarios like this.

You can refer the documentation here

It states

Sometimes you need to trigger a navigation action from places where you do not have access to the navigation prop, such as a Redux middleware. For such cases, you can dispatch navigation actions from the navigation container

Which exactly is your requirement, here we create a navigationref and use call the navigation methods from there.

The below is the code for a simple example, you can use the 'navigate' inside your reducer. Also you will have to move it to a separate file just like they've provided in the documetation.

import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const navigationRef = React.createRef();

function navigate(name, params) {
  navigationRef.current && navigationRef.current.navigate(name, params);
}

function Home() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Go to Settings"
        onPress={() => navigate('Settings', { userName: 'Lucy' })}
      />
    </View>
  );
}

function Settings({ route }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Hello {route.params.userName}</Text>
      <Button title="Go to Home" onPress={() => navigate('Home')} />
    </View>
  );
}

const RootStack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer ref={navigationRef}>
      <RootStack.Navigator>
        <RootStack.Screen name="Home" component={Home} />
        <RootStack.Screen name="Settings" component={Settings} />
      </RootStack.Navigator>
    </NavigationContainer>
  );
}
Related