Reputation: 1399
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()
.
getStateForAction()
for every screen name we have? Create a reducer for them each? router.getActionForPathAndParams()
then?Thanks
Upvotes: 2
Views: 987
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