Skip to content

Commit 91b3f4d

Browse files
committed
Update README.md
1 parent 7e1346d commit 91b3f4d

File tree

1 file changed

+226
-51
lines changed

1 file changed

+226
-51
lines changed

README.md

Lines changed: 226 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,255 @@ react-redux
44
Higher-order React components for [Redux](https://github.com/gaearon/redux).
55

66
- [Quick Start](#quick-start)
7-
- [Components](#components)
7+
- [Recommended API](#recommended-api)
8+
- [`connect`](#connect)
89
- [`Provider`](#provider)
10+
- [Deprecated API](#deprecated-api)
911
- [`Connector`](#connector)
10-
- [Decorators](#decorators)
12+
- [`provide`](#provide)
1113

1214
## Quick Start
1315

14-
Hooking up the Counter example into React looks like this:
16+
React bindings for Redux embrace the idea of [dividing “smart” and “dumb” components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0).
17+
18+
It is advisable that only top-level components of your app (such as route handlers, for example) are aware of Redux. Components below them should be “dumb” and receive all data via props.
19+
20+
<center>
21+
<table>
22+
<thead>
23+
<tr>
24+
<th></th>
25+
<th>Location</th>
26+
<th>Use React-Redux</th>
27+
<th>To read data, they</th>
28+
<th>To change data, they</th>
29+
</tr>
30+
</thead>
31+
<tbody>
32+
<tr>
33+
<td>“Smart” Components</td>
34+
<td>Top level, route handlers</td>
35+
<td>Yes</th>
36+
<td>Subscribe to Redux state</td>
37+
<td>Dispatch Redux actions</td>
38+
</tr>
39+
<tr>
40+
<td>“Dumb” Components</td>
41+
<td>Middle and leaf components</td>
42+
<td>No</th>
43+
<td>Read data from props</td>
44+
<td>Invoke callbacks from props</td>
45+
</tr>
46+
</tbody>
47+
</table>
48+
</center>
49+
50+
### “Dumb” component is unaware of Redux
51+
52+
Let’s say we have a `<Counter />` “dumb” component with a number `counter` prop, and an `increment` function prop that it will call when user presses an “Increment” button:
1553

1654
```js
17-
import { bindActionCreators } from 'redux';
18-
import { Provider, Connector } from 'react-redux';
55+
import { Component } from 'react';
56+
57+
export default class Counter extends Component {
58+
render() {
59+
return (
60+
<button onClick={this.props.increment}>
61+
{this.props.counter}
62+
</button>
63+
);
64+
}
65+
}
66+
```
67+
68+
### “Smart” component is `connect()`-ed to Redux
69+
70+
Here’s how we hook it up to the Redux Store.
71+
72+
We will use `connect()` function provided by `react-redux` to turn a “dumb” `Counter` into a smart component. With the current API, we’ll need to add an intermediate `CounterContainer` component, but we will soon make `connect` API more powerful so this won’t be required. The `connect()` function lets you specify *which exactly* state from the Redux store your component wants to track. This lets you subscribe on any level of granularity.
73+
74+
Our `CounterContainer` necessary to hook `Counter` up to a Redux store looks like this:
75+
76+
```js
77+
import { Component } from 'react';
78+
import { connect } from 'react-redux';
79+
80+
// Assuming this is our “dumb” counter
81+
import Counter from '../components/Counter';
82+
83+
// Assuming these are Redux action creators
84+
import { increment } from './actionCreators';
85+
86+
function select(state) {
87+
// Which part of the Redux global state does our component want to receive as props?
88+
return {
89+
counter: state.counter
90+
};
91+
}
92+
93+
class CounterContainer {
94+
render() {
95+
// connect() call below will inject `dispatch` and
96+
// every key returned by `select` as props into our container:
97+
const { dispatch, counter } = this.props;
98+
99+
// render our “dumb” component, hooking up state to data props
100+
// and using “dispatch action produced by this action creator” as callbacks.
101+
// this is a “bridge” between a Redux-aware world above and Redux-unaware world below.
102+
103+
return (
104+
<Counter counter={counter}
105+
increment={() => dispatch(increment())} />
106+
);
107+
}
108+
}
109+
110+
// Don't forget to actually use connect!
111+
export default connect(select)(CounterContainer);
112+
113+
// You might have noticed that we used parens twice.
114+
// This is called partial applications, and it lets people
115+
// use ES7 decorator proposal syntax:
116+
//
117+
// @connect(select)
118+
// export default class CounterContainer { ... }
119+
//
120+
// Don’t forget decorators are experimental! And they
121+
// desugar to function calls anyway as example above demonstrates.
122+
```
19123

20-
// store setup left out... see the Redux documentation for initializing action creators, reducers and the store.
124+
As you can see, action creators in Redux just return actions, but we need to manually “bind” them to the `dispatch` function for our Redux store. Why don’t we bind action creators to a store right away? This is because of the so-called “universal” apps that need to render on the server. They would have a different store instance for every request, so we don’t know the store instance during the definition!
125+
126+
### Binding many action creators
127+
128+
Binding can get cumbersome, so Redux provides a `bindActionCreators` helper to turn many action creator methods into an object with methods called the same, but bound to a particular `dispatch` function:
129+
130+
```js
131+
132+
import { Component } from 'react';
133+
import { connect } from 'react-redux';
134+
135+
// A helper provided by Redux!
136+
import { bindActionCreators } from 'redux';
137+
// Import many action creators as a single object (like `require('./actionCreators')` in CommonJS)
138+
import * as CounterActionCreators from './actionCreators';
139+
import Counter from '../components/Counter';
21140

22141
function select(state) {
23-
return { counter: state.counter };
142+
return {
143+
counter: state.counter
144+
};
24145
}
25-
class CounterApp {
146+
147+
class CounterContainer {
26148
render() {
149+
const { dispatch, counter } = this.props;
150+
151+
// This time, we use `bindActionCreators` to bind many action creators
152+
// to a particular dispatch function from our Redux store.
153+
27154
return (
28-
<Connector select={select}>
29-
{({ counter, dispatch }) =>
30-
/* Yes this is child as a function. See the Connector section for why this is. */
31-
<Counter counter={counter}
32-
{...bindActionCreators(CounterActions, dispatch)} />
33-
}
34-
</Connector>
155+
<Counter counter={counter}
156+
{...bindActionCreators(CounterActionCreators, dispatch)} />
35157
);
36158
}
37159
}
38160

39-
const containerElement = document.getElementByID('container');
40-
React.run((
161+
// Don't forget to actually use connect!
162+
export default connect(select)(CounterContainer);
163+
```
164+
165+
You can have many `connect()`-ed components in your app at any depth, and you can even nest them. It is however preferable that you try to only `connect()` top-level components such as route handlers, so the data flow in your application stays predictable.
166+
167+
### Injecting Redux store
168+
169+
Finally, how do we actually hook it up to a Redux store? We need to create the store somewhere at the root of our component hierarchy. For client apps, the root component is a good place. For server rendering, you can do this in the request handler.
170+
171+
The trick is to wrap the whole view hierarchy into `<Provider>{() => ... }</Provider>` where `Provider` is imported from `react-redux`. One gotcha is that **the child of `Provider` must be a function**. This is to work around an issue with how context (undocumented feature we have to rely on to pass Redux data to components below) works in React 0.13. In React 0.14, you will be able to put your view hierarchy in `<Provider>` without wrapping it into a function.
172+
173+
```js
174+
import { Provider } from 'react-redux';
175+
176+
class App {
177+
render() {
178+
// ...
179+
}
180+
}
181+
182+
const targetEl = document.getElementById('root');
183+
184+
React.render((
41185
<Provider store={store}>
42-
{() => <CounterApp />}
186+
{() => <App />}
43187
</Provider>
44-
), containerElement);
188+
), targetEl);
189+
190+
// or, if you use React Router 0.13,
191+
192+
// Router.run(routes, Router.HistoryLocation, (Handler) => {
193+
// React.render(
194+
// <Provider store={store}>
195+
// {() => <Handler />}
196+
// </Provider>,
197+
// targetEl
198+
// );
199+
// });
200+
201+
// or, if you use React Router 1.0,
202+
// React.render(
203+
// <Provider store={store}>
204+
// {() => <Router history={history}>...</Router>}
205+
// </Provider>,
206+
// targetEl
207+
// );
45208
```
46209

47-
## Components
210+
## Recommended API
211+
212+
### `connect`
213+
214+
```js
215+
export default connect(select)(MyComponent);
216+
```
217+
218+
Returns a component class that injects the Redux Store’s `dispatch` as a prop into `Component` so it can dispatch Redux actions.
219+
220+
The returned component also subscribes to the updates of Redux store. Any time the state changes, it calls the `select` function passed to it. The selector function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. Use [reselect](https://github.com/faassen/reselect) to efficiently compose selectors and memoize derived data.
221+
222+
Both `dispatch` and every property returned by `select` will be provided to your `Component` as `props`.
223+
224+
It is the responsibility of a Smart Component to bind action creators to the given `dispatch` function and pass those
225+
bound creators to Dumb Components. Redux provides a `bindActionCreators` to streamline the process of binding action
226+
creators to the dispatch function.
227+
228+
**To use `connect()`, the root component of your app must be wrapped into `<Provider>{() => ... }</Provider>` before being rendered.**
229+
230+
See the usage example in the quick start above.
48231

49232
### `Provider`
50233

234+
```js
235+
<Provider store={store}>
236+
{() => <MyRootComponent>}
237+
</Provider>
238+
```
239+
51240
The `Provider` component takes a `store` prop and a [function as a child](#child-must-be-a-function) with your root
52241
component. The `store` is then passed to the child via React's `context`. This is the entry point for Redux and must be
53242
present in order to use the `Connector` component.
54243

244+
## Deprecated API
245+
55246
### `Connector`
56247

57-
Components in React can be divided into two categories: Dumb Components, which have no knowledge of your application's
58-
state and focus on a specific piece of functionality; and Smart Components which take in your application's state
59-
and stich together Dumb Components. This library has a Higher-Order Component called `Connector` for providing specific
60-
pieces of state to a Smart Component automatically and handling store changes gracefully.
248+
>**Note**
249+
>Deprecated. Use `connect()` instead.
250+
251+
```js
252+
<Connector select={fn}>
253+
{props => <MyComponent {...props} />}
254+
</Connector>
255+
```
61256

62257
Similar to `Provider`, the `Connector` expects a single [function as a child](#child-must-be-a-function) and a function
63258
as the `select` prop. The selector function takes a single argument of the entire root store and returns an object to be
@@ -68,35 +263,15 @@ It is the responsibility of a Smart Component to bind action creators to the giv
68263
bound creators to Dumb Components. Redux provides a `bindActionCreators` to streamline the process of binding action
69264
creators to the dispatch function.
70265

71-
#### Child must be a function
72-
73-
React's context feature is technically not feature complete and has a bug in the current (0.13) release. The work around
74-
for this bug is to pass a function as the child which will then return the Component desired.
266+
We don’t recommend its use anymore because it’s not as flexible as `connect()` and has some performance implications for more complex scenarios.
75267

76-
## Decorators
268+
### `provide`
77269

78-
ECMA Script 7 introduces a new syntactic feature called Decorators. `react-redux` comes with two decorators to simply
79-
creating smart components and providing the store at the top level. Here is the same example at the top of this document
80-
using decorators:
270+
>**Note**
271+
>Deprecated. Use `<Provider>` instead.
81272
82273
```js
83-
import { bindActionCreators } from 'redux';
84-
import { connect, provide } from 'react-redux';
85-
86-
// store setup left out... see the Redux documentation for initializing action creators, reducers and the store.
87-
88-
// Note: you do *not* have to `@provide` every component you `@connect`, but this abritrarily simple example only has
89-
// one Smart Component at the top level. A more complete example may have a root level component that is only decorated
90-
// with `@provide` and many smart components decorated with `@connect`.
91-
92-
@provide(store)
93-
@connect((state) => ({ counter: state.counter }))
94-
class CounterApp {
95-
render() {
96-
return <Counter counter={counter} {...bindActionCreators(CounterActions, dispatch)} />;
97-
}
98-
}
99-
100-
const containerElement = document.getElementByID('container');
101-
React.run(<CounterApp />, containerElement);
274+
export default provide(store)(MyRootComponent);
102275
```
276+
277+
This higher-order component provides the same functionality as `<Provider>`. We don’t recommend it anymore because it’s less flexible than `<Provider>` and doesn’t work with [redux-devtools](http://github.com/gaearon/redux-devtools) or server rendering.

0 commit comments

Comments
 (0)