diff --git a/docs/api/README.md b/docs/api/README.md index 6fb8ba3426..d49581bd85 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -6,7 +6,7 @@ hide_title: true # API Reference -The Redux API surface is tiny. Redux defines a set of contracts for you to implement (such as [reducers](../Glossary.md#reducer)) and provides a few helper functions to tie these contracts together. +The Redux API surface is tiny. Redux defines a set of contracts for you to implement (such as [reducers](../understanding/thinking-in-redux/Glossary.md#reducer)) and provides a few helper functions to tie these contracts together. This section documents the complete Redux API. Keep in mind that Redux is only concerned with managing the state. In a real app, you'll also want to use UI bindings like [react-redux](https://github.com/gaearon/react-redux). diff --git a/docs/api/Store.md b/docs/api/Store.md index c9c9e3c899..72f0e536b6 100644 --- a/docs/api/Store.md +++ b/docs/api/Store.md @@ -6,15 +6,15 @@ hide_title: true # Store -A store holds the whole [state tree](../Glossary.md#state) of your application. -The only way to change the state inside it is to dispatch an [action](../Glossary.md#action) on it. +A store holds the whole [state tree](../understanding/thinking-in-redux/Glossary.md#state) of your application. +The only way to change the state inside it is to dispatch an [action](../understanding/thinking-in-redux/Glossary.md#action) on it. A store is not a class. It's just an object with a few methods on it. -To create it, pass your root [reducing function](../Glossary.md#reducer) to [`createStore`](createStore.md). +To create it, pass your root [reducing function](../understanding/thinking-in-redux/Glossary.md#reducer) to [`createStore`](createStore.md). > ##### A Note for Flux Users > -> If you're coming from Flux, there is a single important difference you need to understand. Redux doesn't have a Dispatcher or support many stores. **Instead, there is just a single store with a single root [reducing function](../Glossary.md#reducer).** As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree. You can use a helper like [`combineReducers`](combineReducers.md) to combine them. This is similar to how there is just one root component in a React app, but it is composed out of many small components. +> If you're coming from Flux, there is a single important difference you need to understand. Redux doesn't have a Dispatcher or support many stores. **Instead, there is just a single store with a single root [reducing function](../understanding/thinking-in-redux/Glossary.md#reducer).** As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree. You can use a helper like [`combineReducers`](combineReducers.md) to combine them. This is similar to how there is just one root component in a React app, but it is composed out of many small components. ### Store Methods @@ -44,9 +44,9 @@ The store's reducing function will be called with the current [`getState()`](#ge > ##### A Note for Flux Users > -> If you attempt to call `dispatch` from inside the [reducer](../Glossary.md#reducer), it will throw with an error saying “Reducers may not dispatch actions.” This is similar to “Cannot dispatch in a middle of dispatch” error in Flux, but doesn't cause the problems associated with it. In Flux, a dispatch is forbidden while Stores are handling the action and emitting updates. This is unfortunate because it makes it impossible to dispatch actions from component lifecycle hooks or other benign places. +> If you attempt to call `dispatch` from inside the [reducer](../understanding/thinking-in-redux/Glossary.md#reducer), it will throw with an error saying “Reducers may not dispatch actions.” This is similar to “Cannot dispatch in a middle of dispatch” error in Flux, but doesn't cause the problems associated with it. In Flux, a dispatch is forbidden while Stores are handling the action and emitting updates. This is unfortunate because it makes it impossible to dispatch actions from component lifecycle hooks or other benign places. > -> In Redux, subscriptions are called after the root reducer has returned the new state, so you _may_ dispatch in the subscription listeners. You are only disallowed to dispatch inside the reducers because they must have no side effects. If you want to cause a side effect in response to an action, the right place to do this is in the potentially async [action creator](../Glossary.md#action-creator). +> In Redux, subscriptions are called after the root reducer has returned the new state, so you _may_ dispatch in the subscription listeners. You are only disallowed to dispatch inside the reducers because they must have no side effects. If you want to cause a side effect in response to an action, the right place to do this is in the potentially async [action creator](../understanding/thinking-in-redux/Glossary.md#action-creator). #### Arguments @@ -60,7 +60,7 @@ The store's reducing function will be called with the current [`getState()`](#ge The “vanilla” store implementation you get by calling [`createStore`](createStore.md) only supports plain object actions and hands them immediately to the reducer. -However, if you wrap [`createStore`](createStore.md) with [`applyMiddleware`](applyMiddleware.md), the middleware can interpret actions differently, and provide support for dispatching [async actions](../Glossary.md#async-action). Async actions are usually asynchronous primitives like Promises, Observables, or thunks. +However, if you wrap [`createStore`](createStore.md) with [`applyMiddleware`](applyMiddleware.md), the middleware can interpret actions differently, and provide support for dispatching [async actions](../understanding/thinking-in-redux/Glossary.md#async-action). Async actions are usually asynchronous primitives like Promises, Observables, or thunks. Middleware is created by the community and does not ship with Redux by default. You need to explicitly install packages like [redux-thunk](https://github.com/gaearon/redux-thunk) or [redux-promise](https://github.com/acdlite/redux-promise) to use it. You may also create your own middleware. diff --git a/docs/api/applyMiddleware.md b/docs/api/applyMiddleware.md index 8e1b9e23ed..0c74fe5d6c 100644 --- a/docs/api/applyMiddleware.md +++ b/docs/api/applyMiddleware.md @@ -8,7 +8,7 @@ hide_title: true Middleware is the suggested way to extend Redux with custom functionality. Middleware lets you wrap the store's [`dispatch`](Store.md#dispatchaction) method for fun and profit. The key feature of middleware is that it is composable. Multiple middleware can be combined together, where each middleware requires no knowledge of what comes before or after it in the chain. -The most common use case for middleware is to support asynchronous actions without much boilerplate code or a dependency on a library like [Rx](https://github.com/Reactive-Extensions/RxJS). It does so by letting you dispatch [async actions](../Glossary.md#async-action) in addition to normal actions. +The most common use case for middleware is to support asynchronous actions without much boilerplate code or a dependency on a library like [Rx](https://github.com/Reactive-Extensions/RxJS). It does so by letting you dispatch [async actions](../understanding/thinking-in-redux/Glossary.md#async-action) in addition to normal actions. For example, [redux-thunk](https://github.com/gaearon/redux-thunk) lets the action creators invert control by dispatching functions. They would receive [`dispatch`](Store.md#dispatchaction) as an argument and may call it asynchronously. Such functions are called _thunks_. Another example of middleware is [redux-promise](https://github.com/acdlite/redux-promise). It lets you dispatch a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) async action, and dispatches a normal action when the Promise resolves. @@ -219,7 +219,7 @@ export default connect(state => ({ This makes it easier for bundling tools to cut out unneeded modules and reduces the size of your builds. -- Ever wondered what `applyMiddleware` itself is? It ought to be an extension mechanism more powerful than the middleware itself. Indeed, `applyMiddleware` is an example of the most powerful Redux extension mechanism called [store enhancers](../Glossary.md#store-enhancer). It is highly unlikely you'll ever want to write a store enhancer yourself. Another example of a store enhancer is [redux-devtools](https://github.com/reduxjs/redux-devtools). Middleware is less powerful than a store enhancer, but it is easier to write. +- Ever wondered what `applyMiddleware` itself is? It ought to be an extension mechanism more powerful than the middleware itself. Indeed, `applyMiddleware` is an example of the most powerful Redux extension mechanism called [store enhancers](../understanding/thinking-in-redux/Glossary.md#store-enhancer). It is highly unlikely you'll ever want to write a store enhancer yourself. Another example of a store enhancer is [redux-devtools](https://github.com/reduxjs/redux-devtools). Middleware is less powerful than a store enhancer, but it is easier to write. - Middleware sounds much more complicated than it really is. The only way to really understand middleware is to see how the existing middleware works, and try to write your own. The function nesting can be intimidating, but most of the middleware you'll find are, in fact, 10-liners, and the nesting and composability is what makes the middleware system powerful. diff --git a/docs/api/bindActionCreators.md b/docs/api/bindActionCreators.md index ddf04ac2ef..2cbec61d0a 100644 --- a/docs/api/bindActionCreators.md +++ b/docs/api/bindActionCreators.md @@ -6,7 +6,7 @@ hide_title: true # `bindActionCreators(actionCreators, dispatch)` -Turns an object whose values are [action creators](../Glossary.md#action-creator), into an object with the same keys, but with every action creator wrapped into a [`dispatch`](Store.md#dispatchaction) call so they may be invoked directly. +Turns an object whose values are [action creators](../understanding/thinking-in-redux/Glossary.md#action-creator), into an object with the same keys, but with every action creator wrapped into a [`dispatch`](Store.md#dispatchaction) call so they may be invoked directly. Normally you should just call [`dispatch`](Store.md#dispatchaction) directly on your [`Store`](Store.md) instance. If you use Redux with React, [react-redux](https://github.com/gaearon/react-redux) will provide you with the [`dispatch`](Store.md#dispatchaction) function so you can call it directly, too. @@ -16,7 +16,7 @@ For convenience, you can also pass an action creator as the first argument, and #### Parameters -1. `actionCreators` (_Function_ or _Object_): An [action creator](../Glossary.md#action-creator), or an object whose values are action creators. +1. `actionCreators` (_Function_ or _Object_): An [action creator](../understanding/thinking-in-redux/Glossary.md#action-creator), or an object whose values are action creators. 2. `dispatch` (_Function_): A [`dispatch`](Store.md#dispatchaction) function available on the [`Store`](Store.md) instance. diff --git a/docs/api/combineReducers.md b/docs/api/combineReducers.md index e284dca79c..97d4e9bff3 100644 --- a/docs/api/combineReducers.md +++ b/docs/api/combineReducers.md @@ -6,7 +6,7 @@ hide_title: true # `combineReducers(reducers)` -As your app grows more complex, you'll want to split your [reducing function](../Glossary.md#reducer) into separate functions, each managing independent parts of the [state](../Glossary.md#state). +As your app grows more complex, you'll want to split your [reducing function](../understanding/thinking-in-redux/Glossary.md#reducer) into separate functions, each managing independent parts of the [state](../understanding/thinking-in-redux/Glossary.md#state). The `combineReducers` helper function turns an object whose values are different reducing functions into a single reducing function you can pass to [`createStore`](createStore.md). diff --git a/docs/api/compose.md b/docs/api/compose.md index 96b1b5808a..2a52006bd9 100644 --- a/docs/api/compose.md +++ b/docs/api/compose.md @@ -9,7 +9,7 @@ hide_title: true Composes functions from right to left. This is a functional programming utility, and is included in Redux as a convenience. -You might want to use it to apply several [store enhancers](../Glossary.md#store-enhancer) in a row. +You might want to use it to apply several [store enhancers](../understanding/thinking-in-redux/Glossary.md#store-enhancer) in a row. #### Arguments diff --git a/docs/api/createStore.md b/docs/api/createStore.md index 5056ca0d5a..4f1228b8c9 100644 --- a/docs/api/createStore.md +++ b/docs/api/createStore.md @@ -11,7 +11,7 @@ There should only be a single store in your app. #### Arguments -1. `reducer` _(Function)_: A [reducing function](../Glossary.md#reducer) that returns the next [state tree](../Glossary.md#state), given the current state tree and an [action](../Glossary.md#action) to handle. +1. `reducer` _(Function)_: A [reducing function](../understanding/thinking-in-redux/Glossary.md#reducer) that returns the next [state tree](../understanding/thinking-in-redux/Glossary.md#state), given the current state tree and an [action](../understanding/thinking-in-redux/Glossary.md#action) to handle. 2. [`preloadedState`] _(any)_: The initial state. You may optionally specify it to hydrate the state from the server in universal apps, or to restore a previously serialized user session. If you produced `reducer` with [`combineReducers`](combineReducers.md), this must be a plain object with the same shape as the keys passed to it. Otherwise, you are free to pass anything that your `reducer` can understand. diff --git a/docs/faq/ImmutableData.md b/docs/faq/ImmutableData.md index 71a0993534..884b4c438b 100644 --- a/docs/faq/ImmutableData.md +++ b/docs/faq/ImmutableData.md @@ -276,7 +276,7 @@ The store will still be updated with the new values for the root state, but beca **Documentation** - [Recipes: Immutable Update Patterns](../recipes/structuring-reducers/ImmutableUpdatePatterns.md) -- [Troubleshooting: Never mutate reducer arguments](../Troubleshooting.md#never-mutate-reducer-arguments) +- [Troubleshooting: Never mutate reducer arguments](../recipes/Troubleshooting.md#never-mutate-reducer-arguments) ### Why does a reducer mutating the state prevent React-Redux from re-rendering a wrapped component? diff --git a/docs/faq/ReactRedux.md b/docs/faq/ReactRedux.md index ee79002d71..213c0c2c3e 100644 --- a/docs/faq/ReactRedux.md +++ b/docs/faq/ReactRedux.md @@ -54,7 +54,7 @@ Note that “updating data immutably” does _not_ mean that you must use [Immut **Documentation** -- [Troubleshooting](../Troubleshooting.md) +- [Troubleshooting](../recipes/Troubleshooting.md) - [React Redux: Troubleshooting](https://react-redux.js.org/troubleshooting) - [Recipes: Using the Object Spread Operator](../recipes/UsingObjectSpreadOperator.md) - [Recipes: Structuring Reducers - Prerequisite Concepts](../recipes/structuring-reducers/PrerequisiteConcepts.md) diff --git a/docs/recipes/MigratingToRedux.md b/docs/recipes/MigratingToRedux.md index 51c0925bf8..1b64cece0b 100644 --- a/docs/recipes/MigratingToRedux.md +++ b/docs/recipes/MigratingToRedux.md @@ -13,7 +13,7 @@ We don't want to lock you in! ## From Flux -[Reducers](../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), [traditional Flux](https://github.com/facebook/flux), or any other Flux library. +[Reducers](../understanding/thinking-in-redux/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), [traditional Flux](https://github.com/facebook/flux), or any other Flux library. Your process will look like this: diff --git a/docs/recipes/README.md b/docs/recipes/README.md index 2f0caa1da7..00f1777e4d 100644 --- a/docs/recipes/README.md +++ b/docs/recipes/README.md @@ -20,4 +20,5 @@ These are some use cases and code snippets to get you started with Redux in a re - [Isolating Redux Sub-Apps](IsolatingSubapps.md) - [Using Immutable.JS with Redux](UsingImmutableJS.md) - [Code Splitting](CodeSplitting.md) +- [Troubleshooting](Troubleshooting.md) - [Structuring Reducers](structuring-reducers/StructuringReducers.md) diff --git a/docs/recipes/ReducingBoilerplate.md b/docs/recipes/ReducingBoilerplate.md index 4ec813343d..571a3c1934 100644 --- a/docs/recipes/ReducingBoilerplate.md +++ b/docs/recipes/ReducingBoilerplate.md @@ -160,7 +160,7 @@ There are also utility libraries to aid in generating action creators, such as [ ## Async Action Creators -[Middleware](../Glossary.md#middleware) lets you inject custom logic that interprets every action object before it is dispatched. Async actions are the most common use case for middleware. +[Middleware](../understanding/thinking-in-redux/Glossary.md#middleware) lets you inject custom logic that interprets every action object before it is dispatched. Async actions are the most common use case for middleware. Without any middleware, [`dispatch`](../api/Store.md#dispatchaction) only accepts a plain object, so we have to perform AJAX calls inside our components: diff --git a/docs/Troubleshooting.md b/docs/recipes/Troubleshooting.md similarity index 100% rename from docs/Troubleshooting.md rename to docs/recipes/Troubleshooting.md diff --git a/docs/recipes/UsingImmutableJS.md b/docs/recipes/UsingImmutableJS.md index 0bc33b24d5..7dc6bf13a0 100644 --- a/docs/recipes/UsingImmutableJS.md +++ b/docs/recipes/UsingImmutableJS.md @@ -156,7 +156,7 @@ This, together with its performance and rich API for data manipulation, is why I **Documentation** -- [Troubleshooting: Nothing happens when I dispatch an action](../Troubleshooting.md#nothing-happens-when-i-dispatch-an-action) +- [Troubleshooting: Nothing happens when I dispatch an action](./Troubleshooting.md#nothing-happens-when-i-dispatch-an-action) ## What are some opinionated Best Practices for using Immutable.JS with Redux? diff --git a/docs/Glossary.md b/docs/understanding/thinking-in-redux/Glossary.md similarity index 100% rename from docs/Glossary.md rename to docs/understanding/thinking-in-redux/Glossary.md diff --git a/docs/understanding/thinking-in-redux/ThreePrinciples.md b/docs/understanding/thinking-in-redux/ThreePrinciples.md index 008513c35b..7117ce7957 100644 --- a/docs/understanding/thinking-in-redux/ThreePrinciples.md +++ b/docs/understanding/thinking-in-redux/ThreePrinciples.md @@ -11,7 +11,7 @@ Redux can be described in three fundamental principles: ### Single source of truth -**The [global state](../../Glossary.md#state) of your application is stored in an object tree within a single [store](../../Glossary.md#store).** +**The [global state](./Glossary.md#state) of your application is stored in an object tree within a single [store](./Glossary.md#store).** This makes it easy to create universal apps, as the state from your server can be serialized and hydrated into the client with no extra coding effort. A single state tree also makes it easier to debug or inspect an application; it also enables you to persist your app's state in development, for a faster development cycle. Some functionality which has been traditionally difficult to implement - Undo/Redo, for example - can suddenly become trivial to implement, if all of your state is stored in a single tree. @@ -37,7 +37,7 @@ console.log(store.getState()) ### State is read-only -**The only way to change the state is to emit an [action](../../Glossary.md#action), an object describing what happened.** +**The only way to change the state is to emit an [action](./Glossary.md), an object describing what happened.** This ensures that neither the views nor the network callbacks will ever write directly to the state. Instead, they express an intent to transform the state. Because all changes are centralized and happen one by one in a strict order, there are no subtle race conditions to watch out for. As actions are just plain objects, they can be logged, serialized, stored, and later replayed for debugging or testing purposes. @@ -55,7 +55,7 @@ store.dispatch({ ### Changes are made with pure functions -**To specify how the state tree is transformed by actions, you write pure [reducers](../../Glossary.md#reducer).** +**To specify how the state tree is transformed by actions, you write pure [reducers](./Glossary.md#reducer).** Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state objects, instead of mutating the previous state. You can start with a single reducer, and as your app grows, split it off into smaller reducers that manage 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. diff --git a/website/_redirects b/website/_redirects index bdd7a5aa79..f30372243f 100644 --- a/website/_redirects +++ b/website/_redirects @@ -127,8 +127,8 @@ /docs/recipes/reducers/ImmutableUpdatePatterns.html* /recipes/structuring-reducers/immutable-update-patterns:splat /docs/recipes/reducers/InitializingState.html* /recipes/structuring-reducers/initializing-state:splat -/docs/Glossary.html* /glossary:splat -/docs/Troubleshooting.html* /troubleshooting:splat +/docs/Glossary.html* /understanding/thinking-in-redux/glossary:splat +/docs/Troubleshooting.html* /recipes/troubleshooting:splat # Unknown? /introduction/index.html /introduction/getting-started @@ -151,3 +151,6 @@ /introduction/motivation /understanding/thinking-in-redux/motivation /introduction/three-principles /understanding/thinking-in-redux/three-principles /introduction/prior-art /understanding/history-and-design/prior-art + +/glossary /understanding/thinking-in-redux/glossary +/troubleshooting /recipes/troubleshooting diff --git a/website/sidebars.js b/website/sidebars.js index 11a09bac5e..d0b8f3625a 100755 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -8,21 +8,6 @@ module.exports = { 'introduction/ecosystem', 'introduction/examples' ], - 'Understanding Redux': [ - { - type: 'category', - label: 'Thinking in Redux', - items: [ - 'understanding/thinking-in-redux/motivation', - 'understanding/thinking-in-redux/three-principles' - ] - }, - { - type: 'category', - label: 'History and Design', - items: ['understanding/history-and-design/prior-art'] - } - ], Tutorials: [ 'tutorials/tutorials-index', { @@ -78,6 +63,7 @@ module.exports = { 'recipes/isolating-redux-sub-apps', 'recipes/using-immutablejs-with-redux', 'recipes/code-splitting', + 'recipes/troubleshooting', { type: 'category', label: 'Structuring Reducers', @@ -97,6 +83,22 @@ module.exports = { ] } ], + 'Understanding Redux': [ + { + type: 'category', + label: 'Thinking in Redux', + items: [ + 'understanding/thinking-in-redux/motivation', + 'understanding/thinking-in-redux/three-principles', + 'understanding/thinking-in-redux/glossary' + ] + }, + { + type: 'category', + label: 'History and Design', + items: ['understanding/history-and-design/prior-art'] + } + ], FAQ: [ 'faq', 'faq/general', @@ -112,7 +114,6 @@ module.exports = { 'faq/miscellaneous' ], 'Style Guide': ['style-guide/style-guide'], - Other: ['glossary', 'troubleshooting'], 'API Reference': [ 'api/api-reference', 'api/createstore',