Skip to content

Commit c7e37e4

Browse files
committed
Split README into separate docs
1 parent 5efcc08 commit c7e37e4

File tree

8 files changed

+324
-3
lines changed

8 files changed

+324
-3
lines changed

docs/design-goals.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### Philosophy & Design Goals
2+
3+
* You shouldn't need a book on functional programming to use Redux.
4+
* Everything (Stores, Action Creators, configuration) is hot reloadable.
5+
* Preserves the benefits of Flux, but adds other nice properties thanks to its functional nature.
6+
* Prevents some of the anti-patterns common in Flux code.
7+
* Works great in [universal (aka “isomorphic”)](https://medium.com/@mjackson/universal-javascript-4761051b7ae9) apps because it doesn't use singletons and the data can be rehydrated.
8+
* Doesn't care how you store your data: you may use JS objects, arrays, ImmutableJS, etc.
9+
* Under the hood, it keeps all your data in a tree, but you don't need to think about it.
10+
* Lets you efficiently subscribe to finer-grained updates than individual Stores.
11+
* Provides hooks for powerful devtools (e.g. time travel, record/replay) to be implementable without user buy-in.
12+
* Provides extension points so it's easy to [support promises](https://github.com/gaearon/redux/issues/99#issuecomment-112212639) or [generate constants](https://gist.github.com/skevy/8a4ffc3cfdaf5fd68739) outside the core.
13+
* No wrapper calls in your stores and actions. Your stuff is your stuff.
14+
* It's super easy to test things in isolation without mocks.
15+
* You can use “flat” Stores, or [compose and reuse Stores](https://gist.github.com/gaearon/d77ca812015c0356654f) just like you compose Components.
16+
* The API surface area is minimal.
17+
* Have I mentioned hot reloading yet?

docs/examples.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## Examples
2+
3+
### Simple Examples
4+
5+
Redux is distributed with a Counter and a TodoMVC example in its source code.
6+
7+
First, clone the repo:
8+
9+
```
10+
git clone https://github.com/gaearon/redux.git
11+
cd redux
12+
```
13+
14+
Run the Counter example:
15+
16+
```
17+
cd redux/examples/counter
18+
npm install
19+
npm start
20+
```
21+
22+
Run the TodoMVC example:
23+
24+
```
25+
cd ../todomvc
26+
npm install
27+
npm start
28+
```
29+
30+
### Async and Universal Examples with Routing
31+
32+
These async and [universal (aka “isomorphic”)](https://medium.com/@mjackson/universal-javascript-4761051b7ae9) examples using React Router should help you get started:
33+
34+
* [redux-react-router-async-example](https://github.com/emmenko/redux-react-router-async-example): Work in progress. Semi-official. Only the client side. Uses React Router.
35+
* [react-redux-universal-hot-example](https://github.com/erikras/react-redux-universal-hot-example): Universal. Uses React Router.
36+
* [redux-example](https://github.com/quangbuule/redux-example): Universal. Uses Immutable, React Router.
37+
* [isomorphic-counter-example](https://github.com/khtdr/redux-react-koa-isomorphic-counter-example): Universal. A bare-bone implentation of the [counter example app](https://github.com/gaearon/redux/tree/master/examples/counter). Uses promises-middleware to interact with API via Koa on the server.
38+
39+
Don’t be shy, add your own!

docs/getting-started.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
### Actions
2+
3+
```js
4+
// Still using constants...
5+
import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../constants/ActionTypes';
6+
7+
// But action creators are pure functions returning actions
8+
export function increment() {
9+
return {
10+
type: INCREMENT_COUNTER
11+
};
12+
}
13+
14+
export function decrement() {
15+
return {
16+
type: DECREMENT_COUNTER
17+
};
18+
}
19+
20+
// Can also be async if you return a function
21+
export function incrementAsync() {
22+
return dispatch => {
23+
setTimeout(() => {
24+
// Yay! Can invoke sync or async actions with `dispatch`
25+
dispatch(increment());
26+
}, 1000);
27+
};
28+
}
29+
30+
31+
// Could also read state of a store in the callback form
32+
export function incrementIfOdd() {
33+
return (dispatch, getState) => {
34+
const { counter } = getState();
35+
36+
if (counter % 2 === 0) {
37+
return;
38+
}
39+
40+
dispatch(increment());
41+
};
42+
}
43+
```
44+
45+
### Stores
46+
```js
47+
// ... too, use constants
48+
import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../constants/ActionTypes';
49+
50+
// what's important is that Store is a pure function,
51+
// and you can write it anyhow you like.
52+
53+
// the Store signature is (state, action) => state,
54+
// and the state shape is up to you: you can use primitives,
55+
// objects, arrays, or even ImmutableJS objects.
56+
57+
export default function counter(state = 0, action) {
58+
// this function returns the new state when an action comes
59+
switch (action.type) {
60+
case INCREMENT_COUNTER:
61+
return state + 1;
62+
case DECREMENT_COUNTER:
63+
return state - 1;
64+
default:
65+
return state;
66+
}
67+
68+
// BUT THAT'S A SWITCH STATEMENT!
69+
// Right. If you hate 'em, see the FAQ below.
70+
}
71+
```

docs/higher-order-stores.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ A higher-order store is a function that turns a store creating function into a n
77
createStore => createStore'
88
```
99

10-
Look familiar? It's just like the signature for [middleware](middleware.md), only we're wrapping `createStore()` instead of `dispatch()`.
10+
Look familiar? It's just like the signature for [middleware](middleware.md), only we're wrapping `createStore()` instead of `dispatch()`. Like middleware, the key feature of higher-order stores is that they are composable.
1111

12-
Higher-order stores are a pattern for creating composable Redux extensions. They're much the same as higher-order components in React. They can be as simple as `applyMiddleware()`, or as powerful as the Redux Devtools](https://github.com/gaearon/redux-devtools). There's no limit to the kinds of things you can create.
12+
Higher-order stores are much the same as higher-order components in React. They can be as simple as `applyMiddleware()`, or as powerful as the Redux Devtools](https://github.com/gaearon/redux-devtools). There's no limit to the kinds of extensions you can create.
1313

1414
## How it works
1515

docs/middleware.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,56 @@
1-
# Middleware
1+
Middleware
2+
==========
3+
4+
A middleware in Redux is a function that turns a dispatching function into a new dispatching function:
5+
6+
```
7+
dispatch => dispatch'
8+
```
9+
10+
The key feature of middleware is that it is composable. Multiple middleware can be combined together, where each middleware requires no knowledge of the what comes before or after it in the chain.
11+
12+
Usage
13+
=====
14+
15+
To enable middleware in your Redux app, use `applyMiddleware()`.
16+
17+
### `applyMiddleware(...middlewares)`
18+
19+
This function returns a [higher-order store](higher-order store). You don't need to worry about that if you're not interested — here's how you use it:
20+
21+
```js
22+
const store = applyMiddleware(thunk, promise, observable)(createStore)(reducer);
23+
```
24+
25+
Yes, you read that correctly. If this looks strange to you, it may help to break the process down into multiple steps:
26+
27+
```js
28+
const newCreateStore = applyMiddleware(thunk, promise, observable)(createStore);
29+
const store = newCreateStore(reducer);
30+
```
31+
32+
If you
33+
34+
How it works
35+
============
36+
37+
```js
38+
const newDispatch = thunk(promise(observable(dispatch)));
39+
// Or
40+
const newDispatch = compose(thunk, promise, observable, dispatch);
41+
```
42+
43+
`compose` performs function composition. It is the same as `compose()` in underscore or lodash.
44+
45+
You can also use `composeMiddleware()`, which is similar to `compose()` except instead of creating a dispatching function, it creates a middleware function:
46+
47+
```js
48+
const middleware = composeMiddleware(thunk, promise, observable);
49+
const newDispatch = compose(middleware, dispatch);
50+
// Or simply
51+
const newDispatch = compose(dispatch);
52+
```
53+
254

355
A middleware is a function that wraps the `dispatch()` method, or another middleware. For example:
456

docs/react.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
### Components
2+
3+
#### Dumb Components
4+
5+
```js
6+
// The dumb component receives everything using props:
7+
import React, { PropTypes } from 'react';
8+
9+
export default class Counter {
10+
static propTypes = {
11+
increment: PropTypes.func.isRequired,
12+
decrement: PropTypes.func.isRequired,
13+
counter: PropTypes.number.isRequired
14+
};
15+
16+
render() {
17+
const { increment, decrement, counter } = this.props;
18+
return (
19+
<p>
20+
Clicked: {counter} times
21+
{' '}
22+
<button onClick={increment}>+</button>
23+
{' '}
24+
<button onClick={decrement}>-</button>
25+
</p>
26+
);
27+
}
28+
}
29+
```
30+
31+
#### Smart Components
32+
33+
```js
34+
// The smart component may observe stores using `<Connector />`,
35+
// and bind actions to the dispatcher with `bindActionCreators`.
36+
37+
import React from 'react';
38+
import { bindActionCreators } from 'redux';
39+
import { Connector } from 'redux/react';
40+
import Counter from '../components/Counter';
41+
import * as CounterActions from '../actions/CounterActions';
42+
43+
// You can optionally specify `select` for finer-grained subscriptions
44+
// and retrieval. Only when the return value is shallowly different,
45+
// will the child component be updated.
46+
function select(state) {
47+
return { counter: state.counter };
48+
}
49+
50+
export default class CounterApp {
51+
render() {
52+
return (
53+
<Connector select={select}>
54+
{({ counter, dispatch }) =>
55+
/* Yes this is child as a function. */
56+
<Counter counter={counter}
57+
{...bindActionCreators(CounterActions, dispatch)} />
58+
}
59+
</Connector>
60+
);
61+
}
62+
}
63+
```
64+
65+
#### Decorators
66+
67+
The `@connect` decorator lets you create smart components less verbosely:
68+
69+
```js
70+
import React from 'react';
71+
import { bindActionCreators } from 'redux';
72+
import { connect } from 'redux/react';
73+
import Counter from '../components/Counter';
74+
import * as CounterActions from '../actions/CounterActions';
75+
76+
@connect(state => ({
77+
counter: state.counter
78+
}))
79+
export default class CounterApp {
80+
render() {
81+
const { counter, dispatch } = this.props;
82+
// Instead of `bindActionCreators`, you may also pass `dispatch` as a prop
83+
// to your component and call `dispatch(CounterActions.increment())`
84+
return (
85+
<Counter counter={counter}
86+
{...bindActionCreators(CounterActions, dispatch)} />
87+
);
88+
}
89+
}
90+
```
91+
92+
### React Native
93+
94+
To use Redux with React Native, just replace imports from `redux/react` with `redux/react-native`:
95+
96+
```js
97+
import { bindActionCreators } from 'redux';
98+
import { Provider, Connector } from 'redux/react-native';
99+
```

docs/store.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
### Initializing Redux
2+
3+
The simplest way to initialize a Redux instance is to give it an object whose values are your Store functions, and whose keys are their names. You may `import *` from the file with all your Store definitions to obtain such an object:
4+
5+
```js
6+
import { createRedux } from 'redux';
7+
import { Provider } from 'redux/react';
8+
import * as stores from '../stores/index';
9+
10+
const redux = createRedux(stores);
11+
```
12+
13+
Then pass `redux` as a prop to `<Provider>` component in the root component of your app, and you're all set:
14+
15+
```js
16+
export default class App {
17+
render() {
18+
return (
19+
<Provider redux={redux}>
20+
{() =>
21+
<CounterApp />
22+
}
23+
</Provider>
24+
);
25+
}
26+
}
27+
```

docs/universal-rendering.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
### Running the same code on client and server
2+
3+
The `redux` instance returned by `createRedux` also has the `dispatch(action)`, `subscribe()` and `getState()` methods that you may call outside the React components.
4+
5+
You may optionally specify the initial state as the second argument to `createRedux`. This is useful for hydrating the state you received from running Redux on the server:
6+
7+
```js
8+
// server
9+
const redux = createRedux(stores);
10+
redux.dispatch(MyActionCreators.doSomething()); // fire action creators to fill the state
11+
const state = redux.getState(); // somehow pass this state to the client
12+
13+
// client
14+
const initialState = window.STATE_FROM_SERVER;
15+
const redux = createRedux(stores, initialState);
16+
```

0 commit comments

Comments
 (0)