Seregwethrin
Seregwethrin

Reputation: 1399

Redux in React Native without React Navigation state in Redux

I saw Redux Integration page on React Navigation website but I do not understand why we need to store navigation state inside Redux store, can't we just store our application's state with Redux and letting navigator keep its own state?

Because it seems very complicated to integrate router.getStateForAction() and router.getActionForPathAndParams().

Thanks

Upvotes: 2

Views: 987

Answers (1)

artiebits
artiebits

Reputation: 5195

It’s not necessary to store navigation state in reducer. If you don’t need that just keep the app state in reducer and navigation state on its own. Then you can integrate Redux like this:

// App.js

import React from 'react';
import { Provider } from 'react-redux'
import RootNavigator from './src/navigation/RootNavigation';
import configureStore from './src/stores/configureStore';

const store = configureStore();

export default class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <RootNavigator />
      </Provider>
    );
  }
}

But actually, it’s not so complex to integrate navigation state within Redux. And if you do that the navigation state will be automatically updated when you navigate between screens. It so helpful in the complex apps. So, I will just try to explain to you how to use React Navigation and Redux together, maybe you will find it useful in future.

First of all, you configure your StackNavigator as usual:

// navigation/RootNavigator.js

const HomeScreen = () => (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Home Screen</Text>
  </View>
);

const RootNavigator = StackNavigator({
  Home: {
    screen: HomeScreen,
  },
});

export default RootNavigator;

Then you go to reducers folder (if you have one) and create navReducer.js

 // reducers/navReducer.js

import RootNavigator from '../navigation/RootNavigation';

const initialState = RootNavigator.router.getStateForAction(RootNavigator.router.getActionForPathAndParams('Home'));

const navReducer = (state = initialState, action) => {
  const nextState = RootNavigator.router.getStateForAction(action, state);

  // Simply return the original `state` if `nextState` is null or undefined.
  return nextState || state;
};

Where we use RootNavigator.router.getStateForAction just to get navigation state and set it as an initial state of new reducer.

Then combine the reducer with others:

// reducers/index.js

Import navReducer from ‘./navReducer’;

const appReducer = combineReducers({
  nav: navReducer,// updated was nav:nav,
  ...
});

Now we just need to modify our App.js. Now it will looks like:

import React from 'react';
import { Provider, connect } from 'react-redux';
import { addNavigationHelpers } from 'react-navigation';
import RootNavigator from './src/navigation/RootNavigation';
import configureStore from './src/stores/configureStore';
const store = configureStore();

class AppComponent extends React.Component {
  render() {
    return (
      <RootNavigator navigation={addNavigationHelpers({
        dispatch: this.props.dispatch,
        state: this.props.nav,
      })} />
    );
  }
}

const mapStateToProps = (state) => ({
  nav: state.navReducer
});

const AppContainer = connect(mapStateToProps)(AppComponent);

export default () => {
  return (
    <Provider store={store}>
      <AppContainer />
    </Provider>
  )
}

So, you don’t need to wrap each component with addNavigationHelpers, just root component. You don’t need to send/manage actions when navigating between screens. It will be automatically updated.

Upvotes: 2

Related Questions