Skip to content

Commit a0c0567

Browse files
committed
Add Redux integration doc, GA id, update Docusaurus
1 parent 632f660 commit a0c0567

File tree

8 files changed

+3461
-2402
lines changed

8 files changed

+3461
-2402
lines changed

docs/redux-integration.md

Lines changed: 82 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -2,179 +2,132 @@
22
id: redux-integration
33
title: Redux integration
44
sidebar_label: Redux integration
5+
original_id: redux-integration
56
---
67

7-
**Warning: in the next major version of React Navigation, to be released in Fall 2018, we will no longer provide any information about how to integrate with Redux and it may cease to work**. Issues related to Redux that are posted on the React Navigation issue tracker will be immediately closed. Redux integration may continue to work but it will not be tested against or considered when making any design decisions for the library.
8+
It is extremely easy to use Redux in an app with React Navigation. It's basically no different than without React Navigation. The following example shows how to do it end to end: https://snack.expo.io/@react-navigation/redux-example. The most important piece from it is the following:
89

9-
Some folks like to have their navigation state stored in the same place as the rest of their application state. *Think twice before you consider doing this, there is an incredibly good chance that you do not need to do this!*. Storing your React Navigation state in your own Redux store is likely to give you a very difficult time if you don't know what you're doing.
10-
11-
If your only reason for doing this is that you want to be able to perform navigation actions from outside of your components (eg: from a Redux middleware), you can learn more about this in [navigating without the navigation prop](navigating-without-navigation-prop.html).
12-
13-
## Overview
14-
15-
1. To handle your app's navigation state in Redux, you can pass your own [`navigation`](navigation-prop.html) prop to a navigator. `react-navigation-redux-helpers` handles this for you behind the scenes with a "higher-order component" called `reduxifyNavigator`. You pass in your root navigator component to the `reduxifyNavigator` function, and it returns a new component that takes your navigation `state` and `dispatch` function as props.
16-
17-
2. A middleware is needed so that any events that mutate the navigation state properly trigger React Navigation's event listeners.
18-
19-
3. The navigation state inside Redux will need to be kept updated using React Navigation's navigation reducer. You will call this reducer from your Redux master reducer.
20-
21-
## Step-by-step guide
22-
23-
The following steps apply to `react-navigation@^2.3.0` and `react-navigation-redux-helpers@^2.0.0-beta`.
24-
25-
First, you need to add the `react-navigation-redux-helpers` package to your project.
26-
27-
```bash
28-
yarn add react-navigation-redux-helpers
29-
```
30-
31-
or
32-
33-
```bash
34-
npm install --save react-navigation-redux-helpers
35-
```
36-
37-
The following is a minimal example of how you might use navigators within a Redux application:
38-
39-
```es6
40-
import {
41-
createStackNavigator,
42-
} from 'react-navigation';
43-
import {
44-
createStore,
45-
applyMiddleware,
46-
combineReducers,
47-
} from 'redux';
48-
import {
49-
reduxifyNavigator,
50-
createReactNavigationReduxMiddleware,
51-
createNavigationReducer,
52-
} from 'react-navigation-redux-helpers';
53-
import { Provider, connect } from 'react-redux';
54-
import React from 'react';
55-
56-
const AppNavigator = createStackNavigator(AppRouteConfigs);
57-
58-
const navReducer = createNavigationReducer(AppNavigator);
59-
const appReducer = combineReducers({
60-
nav: navReducer,
61-
...
10+
```js
11+
let RootStack = createStackNavigator({
12+
Counter: CounterContainer,
13+
StaticCounter: StaticCounterContainer,
6214
});
6315

64-
// Note: createReactNavigationReduxMiddleware must be run before reduxifyNavigator
65-
const middleware = createReactNavigationReduxMiddleware(
66-
"root",
67-
state => state.nav,
68-
);
69-
70-
const App = reduxifyNavigator(AppNavigator, "root");
71-
const mapStateToProps = (state) => ({
72-
state: state.nav,
73-
});
74-
const AppWithNavigationState = connect(mapStateToProps)(App);
16+
let Navigation = createAppContainer(RootStack);
7517

76-
const store = createStore(
77-
appReducer,
78-
applyMiddleware(middleware),
79-
);
80-
81-
class Root extends React.Component {
18+
// Render the app container component with the provider around it
19+
export default class App extends React.Component {
8220
render() {
8321
return (
8422
<Provider store={store}>
85-
<AppWithNavigationState />
23+
<Navigation />
8624
</Provider>
8725
);
8826
}
8927
}
9028
```
9129

92-
Once you do this, your navigation state is stored within your Redux store, at which point you can fire navigation actions using your Redux dispatch function.
93-
94-
Keep in mind that when a navigator is given a `navigation` prop, it relinquishes control of its internal state. That means you are now responsible for persisting its state, handling any deep linking, [Handling the Hardware Back Button in Android](#handling-the-hardware-back-button-in-android), etc.
95-
96-
Navigation state is automatically passed down from one navigator to another when you nest them. Note that in order for a child navigator to receive the state from a parent navigator, it should be defined as a `screen`.
30+
Notice that we take the component returned from `createAppContainer` and wrap it in a `Provider`. Ta da! Now feel free to use `connect` throughout your app.
9731

98-
Applying this to the example above, you could instead define `AppNavigator` to contain a nested `TabNavigator` as follows:
32+
## What about `navigationOptions`?
9933

100-
```es6
101-
const AppNavigator = createStackNavigator({
102-
Home: { screen: MyTabNavigator },
103-
});
104-
```
34+
Alright fair enough, the answer here isn't the most obvious. Let's say that you want to access the Redux store state from the title, what would you do? There are a couple of options. For these examples let's say that you want to put the count from the above example into the title.
10535

106-
In this case, once you `connect` `AppNavigator` to Redux as is done in `AppWithNavigationState`, `MyTabNavigator` will automatically have access to navigation state as a `navigation` prop.
36+
### Use a component that is `connect`ed
10737

108-
## Full example
38+
Create a component, `connect` it to the store, then use that component in the `title`.
10939

110-
There's a working example app with Redux [here](https://github.com/react-community/react-navigation/tree/master/examples/ReduxExample) if you want to try it out yourself.
111-
112-
## Mocking tests
40+
```js
41+
class Count extends React.Component {
42+
render() {
43+
return <Text>Count: {this.props.value}</Text>
44+
}
45+
}
11346

114-
To make jest tests work with your React Navigation app, you need to change the jest preset in the `package.json`, see [here](https://facebook.github.io/jest/docs/tutorial-react-native.html#transformignorepatterns-customization):
47+
let CountContainer = connect(state => ({ value: state.count }))(Count);
11548

49+
class Counter extends React.Component {
50+
static navigationOptions = {
51+
title: <CountContainer />
52+
};
11653

117-
```json
118-
"jest": {
119-
"preset": "react-native",
120-
"transformIgnorePatterns": [
121-
"node_modules/(?!(jest-)?react-native|react-navigation|react-navigation-redux-helpers)"
122-
]
54+
/* .. the rest of the code */
12355
}
12456
```
12557

126-
## Under the hood
127-
128-
### Creating your own navigation reducer
58+
[See a runnable example](https://snack.expo.io/@react-navigation/redux-example-with-dynamic-title).
12959

130-
If you want to replace `createNavigationReducer` reducer creator this is how you would do it yourself:
60+
### Pass the state you care about as a param to the screen
13161

132-
```es6
133-
const AppNavigator = createStackNavigator(AppRouteConfigs);
62+
If the value isn't expected to change, you can just pass it from a `connect`ed component to the other screen as a param.
13463

135-
const initialState = AppNavigator.router.getStateForAction(AppNavigator.router.getActionForPathAndParams('Login'));
64+
```js
65+
<Button
66+
title="Go to static count screen"
67+
onPress={() =>
68+
this.props.navigation.navigate('StaticCounter', {
69+
count: this.props.count,
70+
})
71+
}
72+
/>
73+
```
13674

137-
const navReducer = (state = initialState, action) => {
138-
const nextState = AppNavigator.router.getStateForAction(action, state);
75+
```js
76+
class StaticCounter extends React.Component {
77+
static navigationOptions = ({ navigation }) => ({
78+
title: navigation.getParam('count'),
79+
});
13980

140-
// Simply return the original `state` if `nextState` is null or undefined.
141-
return nextState || state;
142-
};
81+
render() {
82+
return (
83+
<View style={styles.container}>
84+
<Text style={styles.paragraph}>
85+
{this.props.navigation.getParam('count')}
86+
</Text>
87+
</View>
88+
);
89+
}
90+
}
14391
```
14492

145-
## Handling the Hardware Back Button in Android
93+
[See a runnable example](https://snack.expo.io/@react-navigation/redux-example-with-dynamic-title).
14694

147-
By using the following snippet, your nav component will be aware of the back button press actions and will correctly interact with your stack. This is really useful on Android.
95+
### setParams from your screen
14896

149-
```es6
150-
import React from "react";
151-
import { BackHandler } from "react-native";
152-
import { NavigationActions } from "react-navigation";
97+
Let's modify the `StaticCounter` from the previous example as follows:
15398

154-
/* your other setup code here! this is not a runnable snippet */
99+
```js
100+
class StaticCounter extends React.Component {
101+
static navigationOptions = ({ navigation }) => ({
102+
title: navigation.getParam('count'),
103+
});
155104

156-
class ReduxNavigation extends React.Component {
157105
componentDidMount() {
158-
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
106+
this.updateCount();
159107
}
160108

161-
componentWillUnmount() {
162-
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
109+
componentDidUpdate() {
110+
this.updateCount();
163111
}
164112

165-
onBackPress = () => {
166-
const { dispatch, nav } = this.props;
167-
if (nav.index === 0) {
168-
return false;
169-
}
170-
171-
dispatch(NavigationActions.back());
172-
return true;
173-
};
113+
updateCount() {
114+
this.props.navigation.setParams({ count: this.props.count });
115+
}
174116

175117
render() {
176-
/* more setup code here! this is not a runnable snippet */
177-
return <AppNavigator navigation={navigation} />;
118+
return (
119+
<View style={styles.container}>
120+
<Text style={styles.paragraph}>
121+
{this.props.navigation.getParam('count')}
122+
</Text>
123+
</View>
124+
);
178125
}
179126
}
180127
```
128+
129+
Now whenever the store updates we update the `count` param and the title updates accordingly.
130+
131+
## Can I store the navigation state in Redux too?
132+
133+
This is technically possible, but we don't recommend it - it's too easy to shoot yourself in the foot and slow down / break your app. We encourage you to leave it up to React Navigation to manage the navigation state. But if you really want to do this, you can use [react-navigation-redux-helpers](https://github.com/react-navigation/react-navigation-redux-helpers), but this isn't an officially supported workflow.

0 commit comments

Comments
 (0)