Skip to content

Rewrite the docs #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 98 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
cc6700b
Meh
gaearon Jul 23, 2015
216437b
Update README.md
gaearon Jul 23, 2015
6daf229
What do we need?
gaearon Jul 23, 2015
8604261
Update README.md
gaearon Jul 23, 2015
f0a1f5c
Update README.md
gaearon Jul 23, 2015
17f4009
Update README.md
gaearon Jul 23, 2015
90d65cb
Update README.md
gaearon Jul 23, 2015
323d7b9
New docs directory structure
gaearon Jul 23, 2015
c27f274
New docs directory structure
gaearon Jul 23, 2015
deb43bb
New docs directory structure
gaearon Jul 23, 2015
89b022a
Delete ROADMAP.md
gaearon Jul 23, 2015
5766388
Whatever
gaearon Jul 23, 2015
fe6c975
Update tagline
gaearon Jul 23, 2015
74d5988
Update Core Ideas.md
gaearon Jul 23, 2015
e19bdec
Doc structure
gaearon Jul 23, 2015
b1fdcd6
Update README.md
gaearon Jul 23, 2015
bb5a332
Update README.md
gaearon Jul 23, 2015
3d0b3ae
Update README.md
gaearon Jul 23, 2015
cc17f47
Update README.md
gaearon Jul 23, 2015
3045ffd
Update README.md
gaearon Jul 23, 2015
c49ff25
Merge branch 'rewrite-docs' of github.com:gaearon/redux into rewrite-…
gaearon Jul 23, 2015
96d3eeb
Update README.md
gaearon Jul 23, 2015
780a0b1
Update README.md
gaearon Jul 23, 2015
982ce3a
Update README.md
gaearon Jul 23, 2015
87b4b16
Doc structure
gaearon Jul 23, 2015
eed7183
Update README.md
gaearon Jul 23, 2015
c54db71
Update README.md
gaearon Jul 23, 2015
888f6e2
Update README.md
gaearon Jul 23, 2015
a51b0f4
Doc structure
gaearon Jul 23, 2015
f70d066
Update README.md
gaearon Jul 23, 2015
7ca6f14
Update README.md
gaearon Jul 23, 2015
bb1d192
lol
gaearon Jul 23, 2015
4e01227
Update README.md
gaearon Jul 23, 2015
942bcfe
Update README.md
gaearon Jul 23, 2015
c7f1315
Update README.md
gaearon Jul 23, 2015
f9c0264
Update README.md
gaearon Jul 23, 2015
d7bfb6e
Update README.md
gaearon Jul 23, 2015
9332f00
Update README.md
gaearon Jul 23, 2015
c8de1ac
Update README.md
gaearon Jul 23, 2015
608c18c
Update Core Ideas.md
gaearon Jul 23, 2015
a804887
Update Core Ideas.md
gaearon Jul 23, 2015
63dfe6e
Update Getting Started.md
gaearon Jul 23, 2015
b013165
Update Migrating to Redux.md
gaearon Jul 23, 2015
5cde95d
Update Relation to Other Libraries.md
gaearon Jul 23, 2015
644c48f
Rename What Goes in Userland.md to Userland and Core.md
gaearon Jul 23, 2015
260fb94
Update The Redux Flow.md
gaearon Jul 23, 2015
cf432dc
Update Userland and Core.md
gaearon Jul 23, 2015
50880cf
Update Why Redux.md
gaearon Jul 23, 2015
7b0473d
Update Glossary.md
gaearon Jul 23, 2015
d0b86f1
Update Glossary.md
gaearon Jul 23, 2015
6d58b00
Update API.md
gaearon Jul 24, 2015
40149cd
Update API.md
gaearon Jul 24, 2015
470bb06
Update API.md
gaearon Jul 24, 2015
4e64d47
Update API.md
gaearon Jul 24, 2015
81b88fb
Update API.md
gaearon Jul 24, 2015
18d7717
Higher-order store => Store enhancer
gaearon Jul 24, 2015
49443da
Update API.md
gaearon Jul 24, 2015
33265b3
Rename Higher Order Stores.md to Stores Enhancers.md
gaearon Jul 24, 2015
2fca51d
Update Migrating to Redux.md
gaearon Jul 24, 2015
80a0cf8
Add TOC to API.md
ellbee Jul 24, 2015
3055a83
Merge pull request #319 from ellbee/api-doc
gaearon Jul 25, 2015
5c2ce3f
Add missing paren
moroshko Jul 25, 2015
da33002
Remove duplicate text
moroshko Jul 25, 2015
e5e073b
Fix "action creators" link
moroshko Jul 25, 2015
808c32d
Fix `bindActionCreators` example
moroshko Jul 25, 2015
42a9e58
Change `<Func>` to `<Function>` for consistency
moroshko Jul 25, 2015
70fda76
Merge pull request #324 from moroshko/patch-4
gaearon Jul 25, 2015
c589d09
Merge pull request #321 from moroshko/patch-1
gaearon Jul 25, 2015
0bb099c
Merge pull request #322 from moroshko/patch-2
gaearon Jul 25, 2015
dca1b3c
Merge pull request #323 from moroshko/patch-3
gaearon Jul 25, 2015
e1eb208
Merge pull request #325 from moroshko/patch-5
gaearon Jul 25, 2015
6d6df19
JSDoc improvements for createStore
emmenko Jul 25, 2015
e2f6baf
Revert "JSDoc improvements for createStore"
emmenko Jul 25, 2015
c74a877
feat: add gitbook (#311)
Jul 27, 2015
ecfd127
Update Relation to Other Libraries.md
gaearon Jul 27, 2015
ac9319d
Update Relation to Other Libraries.md
gaearon Jul 27, 2015
1096c55
Update Relation to Other Libraries.md
gaearon Jul 27, 2015
08199a0
Update Relation to Other Libraries.md
gaearon Jul 27, 2015
66a0fb7
Update Why Redux.md
gaearon Jul 27, 2015
df5b9ce
JSDoc improvements
emmenko Jul 25, 2015
273b5d7
Update Userland and Core.md
gaearon Jul 27, 2015
35e7549
Merge pull request #326 from gaearon/jsdoc-improvements
gaearon Jul 27, 2015
6134e6d
Update Migrating to Redux.md
gaearon Jul 27, 2015
a79e436
Update Migrating to Redux.md
gaearon Jul 27, 2015
7b34e44
Update The Redux Flow.md
gaearon Jul 27, 2015
ae1a2e8
Update The Redux Flow.md
gaearon Jul 27, 2015
bbd82b4
Import Getting Started by @acdlite from improve-docs branch
gaearon Jul 27, 2015
cd48b28
less wall of text
gaearon Jul 27, 2015
d0b2ad9
Update The Redux Flow.md
gaearon Jul 27, 2015
b2bf3df
Update The Redux Flow.md
gaearon Jul 27, 2015
3bbf822
Update ordering or things
quicksnap Jul 27, 2015
1b0bac4
Tweaks
quicksnap Jul 27, 2015
1b79b6b
Merge pull request #336 from quicksnap/patch-1
gaearon Jul 27, 2015
19cc441
Grammar fix
quicksnap Jul 27, 2015
45a5445
Merge pull request #338 from quicksnap/patch-2
gaearon Jul 27, 2015
adf31a1
Fix links in Getting Started docs
iamdmhero Jul 27, 2015
1e898af
Merge pull request #339 from aparticka/patch-1
gaearon Jul 27, 2015
24bcecf
Merge pull request #331 from theaqua/feature/311
gaearon Jul 27, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
551 changes: 114 additions & 437 deletions README.md

Large diffs are not rendered by default.

22 changes: 0 additions & 22 deletions ROADMAP.md

This file was deleted.

45 changes: 45 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Summary
* Basics
* [Core Ideas](docs/Basics/Core Ideas.md)
* [Getting Started](docs/Basics/Getting Started.md)
* [Migrating to Redux](docs/Basics/Migrating to Redux.md)
* [Relation to Other Libraries](docs/Basics/Relation to Other Libraries.md)
* [The Redux Flow](docs/Basics/The Redux Flow.md)
* [Userland and Core](docs/Basics/Userland and Core.md)
* [Why Redux](docs/Basics/Why Redux.md)
* Recipes
* [Anti-Patterns](docs/Recipes/Anti-Patterns.md)
* [Asynchronous Data Fetching](docs/Recipes/Asynchronous Data Fetching.md)
* [Authentication](docs/Recipes/Authentication.md)
* [Code Splitting](docs/Recipes/Code Splitting.md)
* [Connecting UI](docs/Recipes/Connecting UI.md)
* [Derived Data](docs/Recipes/Derived Data.md)
* [Developer Tools](docs/Recipes/Developer Tools.md)
* [Expressing Dependencies](docs/Recipes/Expressing Dependencies.md)
* [Hot Reloading](docs/Recipes/Hot Reloading.md)
* [Immutability](docs/Recipes/Immutability.md)
* [Logging](docs/Recipes/Logging.md)
* [Middleware](docs/Recipes/Middleware.md)
* [Optimistic Updates](docs/Recipes/Optimistic Updates.md)
* [Optimizing Performance](docs/Recipes/Optimizing Performance.md)
* [Pagination](docs/Recipes/Pagination.md)
* [React Native](docs/Recipes/React Native.md)
* [React Router](docs/Recipes/React Router.md)
* [React](docs/Recipes/React.md)
* [Recording and Replaying](docs/Recipes/Recording and Replaying.md)
* [Relay and GraphQL](docs/Recipes/Relay and GraphQL.md)
* [Side Effects](docs/Recipes/Side Effects.md)
* [Stores Enhancers](docs/Recipes/Stores Enhancers.md)
* [Thunks, Promises and Observables](docs/Recipes/Thunks, Promises and Observables.md)
* [Time Travel](docs/Recipes/Time Travel.md)
* [Undo and Redo](docs/Recipes/Undo and Redo.md)
* [Unit Testing](docs/Recipes/Unit Testing.md)
* [Universal Apps](docs/Recipes/Universal Apps.md)
* Reference
* [API](docs/Reference/API.md)
* [Glossary](docs/Reference/Glossary.md)
* Resources
* [Articles](docs/Resources/Articles.md)
* [Examples](docs/Resources/Examples.md)
* [Getting Help](docs/Resources/Getting Help.md)
* [Utilities](docs/Resources/Utilities.md)
14 changes: 14 additions & 0 deletions docs/Basics/Core Ideas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Core Ideas
--------------------------

Redux can be described in three fundamental principles:

* **The whole state of your app is stored in an object tree inside a single *store*.** This makes it easy to create universal apps. The state from the server can be serialized and hydrated into the client with no extra coding effort. You can also persist your app’s state in development for a faster development cycle. And of course, with a single state tree, you get the previously difficult functionality like Undo/Redo for free.

* **The only way to mutate the state is to emit an *action*, an object describing what happened.** This ensures that the views or the network callbacks never write directly to the state, and instead express the intent to mutate. Because all mutations are centralized and happen one by one in a strict order, there are no subtle race conditions to watch out for. Actions are just plain objects, so they can be logged, serialized, stored, and later replayed for debugging or testing purposes.

* **To specify how the state tree is transformed by the actions, you write pure *reducers*.** Reducers are just pure functions that take the previous state and the action, and return the next state. You can start with a single reducer, but as your app grows, you can split it into smaller reducers that manage the specific parts of the state tree. Because reducers are just functions, you can control the order in which they are called, pass additional data, or even make reusable reducers for common tasks such as pagination.

--------------------------

Next: [Getting Started](Getting Started.md)
256 changes: 256 additions & 0 deletions docs/Basics/Getting Started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
Getting Started
--------------------------

Don't be fooled by all the fancy talk about reducers, middleware, stores enhancers — Redux is incredibly simple. If you’ve ever built a Flux application, you will feel right at home. (If you’re new to Flux, it's easy, too!)

In this guide, we’ll walk through the process of creating a simple Todo app.

### Actions

First, let’s define some actions.

**Actions** are payloads of information that send data from your application to your store. They are the *only* source of information for a store. You send them to the store using `store.dispatch()`.

Here's an example action which represents adding a new todo item:

```js
{
type: ADD_TODO,
payload: {
text: 'Build my first Redux app'
}
}
```

Actions are plain JavaScript objects. By convention, actions should have a `type` field that indicates the type of action being performed. Types should typically be defined as constants and imported from another module. It’s better to use strings than Symbols because strings are serializable.

```js
import { ADD_TODO, REMOVE_TODO } from '../actionTypes';
```

Other than `type`, the structure of an action object is really up to you. If you're interested, check out [Flux Standard Action](https://github.com/acdlite/flux-standard-action) for recommendations on how actions should be constructed.

We need one more action type, for removing todos:

```js
{
type: REMOVE_TODO,
payload: 123
}
```

`payload` in this case indicates the id of the todo we want to remove.

### Action creators

**Action creators** exactly that — functions that create actions. It’s easy to conflate the terms "action" and "action creator," so do your best to use the proper term.

In *other* Flux implementations, action creators often trigger a dispatch when invoked, like so:

```js
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
payload: {
text
}
};
dispatch(action);
}
```

By contrast, in Redux action creators are **pure functions** with zero side-effects. They simply return an action:

```js
function addTodo(text) {
return {
type: ADD_TODO,
payload: {
text
}
};
}
```

This makes them more portable and easier to test. To actually initiate a dispatch, pass the result to the `dispatch()` function:

```js
dispatch(addTodo(text));
dispatch(removeTodo(id));
```

Or create **bound action creator** that automatically dispatches to a particular store instance:

```js
let boundAddTodo = text => dispatch(addTodo(text));
let boundRemoveTodo = id => dispatch(addTodo(id));
```

The `dispatch()` function can be accessed directly from the store as `store.dispatch()`, but more likely you’ll access it using a helper like `connect` from [react-redux](https://github.com/gaearon/react-redux).

### Reducers

Now let’s set up our store to respond to the action we defined above.

Unlike other Flux implementations, Redux only has a single store, rather than a different store for each domain of data in your application. Instead of creating multiple stores that manually manage their own internal state, we create **reducers** that specify how to calculate a slice of the global state in response to new actions.

A reducer looks like this:

```js
(previousState, action) => newState
```

It’s the type of function you would pass to `Array.prototype.reduce(reducer, ?initialValue)`.

This may seem radical, but it turns out that this function signature is sufficient to express the entirety of the store model from traditional Flux — in a purely functional way. **This is the essence of Redux**. It’s what enables all the cool features like hot reloading, time travel, and universal rendering. Aside from all that, though, it's simply a better model for expressing state changes.

[**See Dan's talk at React Europe for more on this topic**](https://www.youtube.com/watch?v=xsSnOQynTHs).

Let’s make a reducer for our Todo app:

```js
const initialState = { todos: [], idCounter: 0 };

function todos(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return {
...state,
todos: [
...state.todos,
{ text: action.payload, id: state.idCounter + 1 }
],
idCounter: state.idCounter + 1
};
case REMOVE_TODO:
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload)
};
default:
return state;
}
}
```

Whoa, what’s going on here? A few things to note:

- `state` is the previous state of the store. Redux will dispatch a dummy action immediately upon creating your store, at which point `state` is undefined. From that point on, `state` is the previous value returned by the reducer.
- We’re using a default parameter to specify the initial state of the store.
- We’re using a switch statement to check the action type.
- **We’re not mutating the previous state** — we're returning a **new** state object based on the **previous** state object.

That last point is especially important: never mutate the previous state object. Always return a new state. Remember, reducers are pure functions, and should not perform mutations or side-effects. Here we’re using the ES7 spread operator to shallow copy old state values to a new object. You can use a library like Immutable.js for a nicer API and better performance, since it uses [persistent data structures](http://en.wikipedia.org/wiki/Persistent_data_structure). Here’s how that same reducer would look using immutable values:

```js
const initialState = Immutable.Map({ todos: [], idCounter: 0 });

function todos(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return state
.update('todos',
todos => todos.push(Immutable.Map({
text: action.payload,
id: state.get('idCounter')
})
))
.set('idCounter', state.get('idCounter') + 1);
case REMOVE_TODO:
return state
.update('todos',
todos => todos.filter(todo => todo.id !== action.payload )
);
default:
return state;
}
}
```

If you’re thinking “yuck, switch statements,” remember that reducers are just functions — you can abstract away these details using helpers. Check out [redux-actions](https://github.com/acdlite/redux-actions) for an example of how to use higher-order functions to create reducers.

### Creating a store

Now we have some action creators and a reducer to handle them. The next step is to create our store.

To create a store, pass a reducer to `createStore()`:

```js
import { createStore } from 'redux';
import todos from '../reducers/todos';
const store = createStore(todos);
```

Usually you’ll have multiple reducers for different domains of data in your app. Consider the following reducers:

```js
export function todos(state, action) {
/* ... */
}

export function counter(state, action) {
/* ... */
}
```

You can use the `combineReducers()` helper to combine multiple reducers into one:

```js
import { createStore, combineReducers } from 'redux';
import * as reducers from '../reducers';
const reducer = combineReducers(reducers);
const store = createStore(reducer);
```

It will create a reducer which produces a state object, whose keys match those of your reducers:

```js
const state = {
todos: todoState,
counter: counterState
};
```

### Middleware

Middleware is an optional feature of Redux that enables you to customize how dispatches are handled. Think of middleware as a certain type of plugin or extension for Redux.

A common use for middleware is to enable asynchronous dispatches. For example, a promise middleware adds support for dispatching promises:

```js
dispatch(Promise.resolve({ type: ADD_TODO, payload: { text: 'Use middleware!' } }));
```
A promise middleware would detect that a promise was dispatched, intercept it, and instead dispatch with the resolved value at a future point in time.

Middleware is very simple to create using function composition. We won't focus on how middleware works in this document but here's how you enable it when creating your store:

```js
import { createStore, applyMiddleware } from 'redux';
// where promise, thunk, and observable are examples of middleware
const store = applyMiddleware(promise, thunk, observable)(createStore)(reducer);
```

Yes, you read that correctly. [Read more about how middleware works here.](../Recipes/Middleware.md)

### Connecting to your views

You’ll rarely interact with the store object directly. Most often, you’ll use some sort of binding to your preferred view library.

Flux is most popular within the React community, but Redux works with any kind of view layer. The React bindings for Redux are available as [react-redux](https://github.com/gaearon/react-redux) — see that project for details on how to integrate with React.

However, if you do find yourself needing to access the store directly, the API for doing so is very simple:

- `store.dispatch()` dispatches an action.
- `store.getState()` gets the current state.
- `store.subscribe()` registers a listener which is called after every dispatch, and returns a function which you call to unsubscribe.


### Go make something great

That’s it! As you can see, despite the powerful features that Redux enables, the core of Redux is really quite simple.

Please let us know if you have suggestions for how this guide could be improved.

--------------------------

Next: [Migrating to Redux](Migrating to Redux.md)
29 changes: 29 additions & 0 deletions docs/Basics/Migrating to Redux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Migrating to Redux
--------------------------

#### From Flux Libraries

[Reducer functions](../Reference/Glossary.md#reducer) capture “the essence” of Flux Stores, so it’s possible to gradually migrate an existing Flux project towards Redux, whether you are using [Flummox](http://github.com/acdlite/flummox), [Alt](http://github.com/goatslacker/alt), [vanilla Flux](https://github.com/facebook/flux), or any other Flux library.

It is also possible to do the reverse and migrate from Redux to any of these libraries following the same steps.

Your process will look like this:

* Create a function called `createFluxStore(reducer)` that creates a Flux store compatible with your existing app from a reducer function. Internally it might look similar to [`createStore`](../../src/createStore.js) implementation from Redux. Its dispatch handler should just call the `reducer` for any action, store the next state, and emit change.

* This allows you to gradually rewrite every Flux Store in your app as a reducer, but still export `createFluxStore(reducer)` so the rest of your app is not aware that this is happening.

* As you rewrite your Stores, you will find that you need to avoid certain Flux anti-patterns such as fetching API inside the Store, or triggering actions inside the Stores. Your Flux code will be easier to follow once as you port it to be based on reducers!

* When you have ported all of your Flux Stores to be implement with reducers, you can replace the Flux library with a single Redux store, and combine those reducers you already have into one using `combineReducers(reducers)`.

* Now all that’s left to do is to port the UI to use Redux bindings for your view library instead of the ones that came with your Flux library, and your app uses Redux!

* Finally, you might want to begin using some Redux idioms like middleware to further simplify your asynchronous code.

#### From Backbone

Sorry, you’ll need to rewrite your model layer :-(.

--------------------------
Next: [Relation to Other Libraries](Relation to Other Libraries.md)
Loading