From c861d345596af4883c31a2461a6a640091674242 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Sat, 8 Dec 2018 12:07:03 +0800 Subject: [PATCH 1/5] Enable versioned doc --- website/pages/en/versions.js | 94 ++++ website/siteConfig.js | 3 +- website/versioned_docs/version-5.1.1/api.md | 492 ++++++++++++++++++ .../version-5.1.1/api/Provider.md | 80 +++ .../versioned_docs/version-5.1.1/api/api.md | 492 ++++++++++++++++++ .../introduction/basic-tutorial.md | 459 ++++++++++++++++ .../version-5.1.1/introduction/quick-start.md | 71 +++ .../introduction/why-use-react-redux.md | 98 ++++ .../version-5.1.1/troubleshooting.md | 88 ++++ ...atching-actions-with-mapDispatchToProps.md | 407 +++++++++++++++ ...ct-extracting-data-with-mapStateToProps.md | 249 +++++++++ .../version-5.1.1-sidebars.json | 20 + website/versions.json | 3 + 13 files changed, 2555 insertions(+), 1 deletion(-) create mode 100644 website/pages/en/versions.js create mode 100644 website/versioned_docs/version-5.1.1/api.md create mode 100644 website/versioned_docs/version-5.1.1/api/Provider.md create mode 100644 website/versioned_docs/version-5.1.1/api/api.md create mode 100644 website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md create mode 100644 website/versioned_docs/version-5.1.1/introduction/quick-start.md create mode 100644 website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md create mode 100644 website/versioned_docs/version-5.1.1/troubleshooting.md create mode 100644 website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md create mode 100644 website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md create mode 100644 website/versioned_sidebars/version-5.1.1-sidebars.json create mode 100644 website/versions.json diff --git a/website/pages/en/versions.js b/website/pages/en/versions.js new file mode 100644 index 000000000..fa44ed876 --- /dev/null +++ b/website/pages/en/versions.js @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + const React = require('react'); + + const CompLibrary = require('../../core/CompLibrary'); + + const Container = CompLibrary.Container; + + const CWD = process.cwd(); + + const siteConfig = require(`${CWD}/siteConfig.js`); + const versions = require(`${CWD}/versions.json`); + + function Versions() { + const latestVersion = versions[0]; + const repoUrl = `https://github.com/${siteConfig.organizationName}/${ + siteConfig.projectName + }`; + const releaseTagUrl = version => `${repoUrl}/releases/tag/v${version}` + return ( +
+ +
+
+

{siteConfig.title} Versions

+
+

New versions of this project are released every so often.

+

Current version (Stable)

+ + + + + + + + +
{latestVersion} + Documentation + + Release Notes +
+

+ This is the version that is configured automatically when you first + install this project. +

+

Pre-release versions

+ + + + + + + + +
{siteConfig.nextVersion} + Documentation + + Release Notes +
+

Past Versions

+ + + {versions.map( + version => + version !== latestVersion && ( + + + + + + ), + )} + +
{version} + Documentation + + Release Notes +
+

+ You can find past versions of this project on{' '} + GitHub. +

+
+
+
+ ); + } + + module.exports = Versions; \ No newline at end of file diff --git a/website/siteConfig.js b/website/siteConfig.js index 155053067..0d7db9a48 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -84,7 +84,8 @@ const siteConfig = { // You may provide arbitrary config keys to be used as needed by your // template. For example, if you need your repo's URL... - repoUrl: "https://github.com/reduxjs/react-redux" + repoUrl: "https://github.com/reduxjs/react-redux", + nextVersion: "6.0.0" }; module.exports = siteConfig; diff --git a/website/versioned_docs/version-5.1.1/api.md b/website/versioned_docs/version-5.1.1/api.md new file mode 100644 index 000000000..4440b6950 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/api.md @@ -0,0 +1,492 @@ +--- +id: version-5.1.1-api +title: Api +sidebar_label: API +hide_title: true +original_id: api +--- + +# API + + +## Provider + +Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. + +If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +### Props + +* `store` (*[Redux Store](https://redux.js.org/api-reference/store)*): The single Redux store in your application. +* `children` (*ReactElement*) The root of your component hierarchy. + +### Example + +#### Vanilla React + +```jsx +ReactDOM.render( + + + , + rootEl +) +``` + +#### React Router + +```jsx +ReactDOM.render( + + + + + + + + , + document.getElementById('root') +) +``` + + +## connect + +``` +connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) +``` + +Connects a React component to a Redux store. `connect` is a facade around `connectAdvanced`, providing a convenient API for the most common use cases. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* [`mapStateToProps(state, [ownProps]): stateProps`] \(*Function*): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into the component’s props. If you don't want to subscribe to store updates, pass `null` or `undefined` in place of `mapStateToProps`. + + If your `mapStateToProps` function is declared as taking two parameters, it will be called with the store state as the first parameter and the props passed to the connected component as the second parameter, and will also be re-invoked whenever the connected component receives new props as determined by shallow equality comparisons. (The second parameter is normally referred to as `ownProps` by convention.) + + >Note: in advanced scenarios where you need more control over the rendering performance, `mapStateToProps()` can also return a function. In this case, *that* function will be used as `mapStateToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + + >The `mapStateToProps` function's first argument is the entire Redux store’s state and it returns an object to be passed as props. It is often called a **selector**. Use [reselect](https://github.com/reduxjs/reselect) to efficiently compose selectors and [compute derived data](https://redux.js.org/recipes/computing-derived-data). + +* [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(*Object* or *Function*): If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a `dispatch` call so they may be invoked directly, will be merged into the component’s props. + + If a function is passed, it will be given `dispatch` as the first parameter. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](https://redux.js.org/api-reference/bindactioncreators) helper from Redux.) + + If your `mapDispatchToProps` function is declared as taking two parameters, it will be called with `dispatch` as the first parameter and the props passed to the connected component as the second parameter, and will be re-invoked whenever the connected component receives new props. (The second parameter is normally referred to as `ownProps` by convention.) + + If you do not supply your own `mapDispatchToProps` function or object full of action creators, the default `mapDispatchToProps` implementation just injects `dispatch` into your component’s props. + + >Note: in advanced scenarios where you need more control over the rendering performance, `mapDispatchToProps()` can also return a function. In this case, *that* function will be used as `mapDispatchToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + +* [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(*Function*): If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, dispatchProps)` is used by default. + +* [`options`] *(Object)* If specified, further customizes the behavior of the connector. In addition to the options passable to `connectAdvanced()` (see those below), `connect()` accepts these additional options: + * [`pure`] *(Boolean)*: If true, `connect()` will avoid re-renders and calls to `mapStateToProps`, `mapDispatchToProps`, and `mergeProps` if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: `true` + * [`areStatesEqual`] *(Function)*: When pure, compares incoming store state to its previous value. Default value: `strictEqual (===)` + * [`areOwnPropsEqual`] *(Function)*: When pure, compares incoming props to its previous value. Default value: `shallowEqual` + * [`areStatePropsEqual`] *(Function)*: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` + * [`areMergedPropsEqual`] *(Function)*: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` + * [`storeKey`] *(String)*: The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + +#### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps + +> Note: `ownProps` **is not passed** to `mapStateToProps` and `mapDispatchToProps` if the formal definition of the function contains one mandatory parameter (function has length 1). For example, functions defined like below won't receive `ownProps` as the second argument. + +```js +function mapStateToProps(state) { + console.log(state); // state + console.log(arguments[1]); // undefined +} +``` +```js +const mapStateToProps = (state, ownProps = {}) => { + console.log(state); // state + console.log(ownProps); // {} +} +``` + +Functions with no mandatory parameters or two parameters **will receive** `ownProps`. +```js +const mapStateToProps = (state, ownProps) => { + console.log(state); // state + console.log(ownProps); // ownProps +} +``` +```js +function mapStateToProps() { + console.log(arguments[0]); // state + console.log(arguments[1]); // ownProps +} +``` +```js +const mapStateToProps = (...args) => { + console.log(args[0]); // state + console.log(args[1]); // ownProps +} +``` + +#### Optimizing connect when options.pure is true + +When `options.pure` is true, `connect` performs several equality checks that are used to avoid unnecessary calls to `mapStateToProps`, `mapDispatchToProps`, `mergeProps`, and ultimately to `render`. These include `areStatesEqual`, `areOwnPropsEqual`, `areStatePropsEqual`, and `areMergedPropsEqual`. While the defaults are probably appropriate 99% of the time, you may wish to override them with custom implementations for performance or other reasons. Here are several examples: + +* You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. For example: `areStatesEqual: (next, prev) => prev.entities.todos === next.entities.todos`; this would effectively ignore state changes for everything but that slice of state. + +* You may wish to override `areStatesEqual` to always return false (`areStatesEqual: () => false`) if you have impure reducers that mutate your store state. (This would likely impact the other equality checks as well, depending on your `mapStateToProps` function.) + +* You may wish to override `areOwnPropsEqual` as a way to whitelist incoming props. You'd also have to implement `mapStateToProps`, `mapDispatchToProps` and `mergeProps` to also whitelist props. (It may be simpler to achieve this other ways, for example by using [recompose's mapProps](https://github.com/acdlite/recompose/blob/master/docs/API.md#mapprops).) + +* You may wish to override `areStatePropsEqual` to use `strictEqual` if your `mapStateToProps` uses a memoized selector that will only return a new object if a relevant prop has changed. This would be a very slight performance improvement, since would avoid extra equality checks on individual props each time `mapStateToProps` is called. + +* You may wish to override `areMergedPropsEqual` to implement a `deepEqual` if your selectors produce complex props. ex: nested objects, new arrays, etc. (The deep equal check should be faster than just re-rendering.) + +### Returns + +A higher-order React component class that passes state and action creators into your component derived from the supplied arguments. This is created by `connectAdvanced`, and details of this higher-order component are covered there. + + +#### Examples + +#### Inject just `dispatch` and don't listen to store + +```js +export default connect()(TodoApp) +``` + +#### Inject all action creators (`addTodo`, `completeTodo`, ...) without subscribing to the store + +```js +import * as actionCreators from './actionCreators' + +export default connect(null, actionCreators)(TodoApp) +``` + +#### Inject `dispatch` and every field in the global state + +>Don’t do this! It kills any performance optimizations because `TodoApp` will rerender after every state change. +>It’s better to have more granular `connect()` on several components in your view hierarchy that each only +>listen to a relevant slice of the state. + +```js +export default connect(state => state)(TodoApp) +``` + +#### Inject `dispatch` and `todos` + +```js +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps)(TodoApp) +``` + +#### Inject `todos` and all action creators + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps, actionCreators)(TodoApp) +``` + +#### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) as `actions` + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { actions: bindActionCreators(actionCreators, dispatch) } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` and a specific action creator (`addTodo`) + +```js +import { addTodo } from './actionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators({ addTodo }, dispatch) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` and specific action creators (`addTodo` and `deleteTodo`) with shorthand syntax + +```js +import { addTodo, deleteTodo } from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +const mapDispatchToProps = { + addTodo, + deleteTodo +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, todoActionCreators as `todoActions`, and counterActionCreators as `counterActions` + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { + todoActions: bindActionCreators(todoActionCreators, dispatch), + counterActions: bindActionCreators(counterActionCreators, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, and todoActionCreators and counterActionCreators together as `actions` + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, and all todoActionCreators and counterActionCreators directly as props + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` of a specific user depending on props + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state, ownProps) { + return { todos: state.todos[ownProps.userId] } +} + +export default connect(mapStateToProps)(TodoApp) +``` + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mergeProps(stateProps, dispatchProps, ownProps) { + return Object.assign({}, ownProps, { + todos: stateProps.todos[ownProps.userId], + addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text) + }) +} + +export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp) +``` + +#### Factory functions + +Factory functions can be used for performance optimizations + +```js +import { addTodo } from './actionCreators' + +function mapStateToPropsFactory(initialState, initialProps) { + const getSomeProperty= createSelector(...); + const anotherProperty = 200 + initialState[initialProps.another]; + return function(state){ + return { + anotherProperty, + someProperty: getSomeProperty(state), + todos: state.todos + } + } +} + +function mapDispatchToPropsFactory(initialState, initialProps) { + function goToSomeLink(){ + initialProps.history.push('some/link'); + } + return function(dispatch){ + return { + addTodo + } + } +} + + +export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp) +``` + +## connectAdvanced + +```js +connectAdvanced(selectorFactory, [connectOptions]) +``` + +Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(*Function*): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. + +* [`connectOptions`] *(Object)* If specified, further customizes the behavior of the connector. + + * [`getDisplayName`] *(Function)*: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` + + * [`methodName`] *(String)*: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` + + * [`renderCountProp`] *(String)*: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` + + * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` + + * [`storeKey`] *(String)*: the key of props/context to get the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + + * [`withRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` + + * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. + + + +### Returns + +A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. + +#### Static Properties + +* `WrappedComponent` *(Component)*: The original component class passed to `connectAdvanced(...)(Component)`. + +#### Static Methods + +All the original static methods of the component are hoisted. + +#### Instance Methods + +##### `getWrappedInstance(): ReactComponent` + +Returns the wrapped component instance. Only available if you pass `{ withRef: true }` as part of the `options` argument. + +### Remarks + +* Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. + +* `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. + + +#### Examples + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function selectorFactory(dispatch) { + let ownProps = {} + let result = {} + const actions = bindActionCreators(actionCreators, dispatch) + const addTodo = (text) => actions.addTodo(ownProps.userId, text) + return (nextState, nextOwnProps) => { + const todos = nextState.todos[nextOwnProps.userId] + const nextResult = { ...nextOwnProps, todos, addTodo } + ownProps = nextOwnProps + if (!shallowEqual(result, nextResult)) result = nextResult + return result + } +} +export default connectAdvanced(selectorFactory)(TodoApp) +``` + +## createProvider + +```js +createProvider([storeKey]) +``` + +Creates a new `` which will set the Redux Store on the passed key of the context. You probably only need this if you are in the inadvisable position of having multiple stores. You will also need to pass the same `storeKey` to the `options` argument of [`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) + +### Arguments + +* [`storeKey`] (*String*): The key of the context on which to set the store. Default value: `'store'` + +### Examples +Before creating multiple stores, please go through this FAQ: [Can or should I create multiple stores?](http://redux.js.org/docs/faq/StoreSetup.html#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) + +```js +import {connect, createProvider} from 'react-redux' + +const STORE_KEY = 'componentStore' + +export const Provider = createProvider(STORE_KEY) + +function connectExtended( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options = {} +) { + options.storeKey = STORE_KEY + return connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options + ) +} + +export {connectExtended as connect} +``` +Now you can import the above `Provider` and `connect` and use them. diff --git a/website/versioned_docs/version-5.1.1/api/Provider.md b/website/versioned_docs/version-5.1.1/api/Provider.md new file mode 100644 index 000000000..7a6ad50f5 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/api/Provider.md @@ -0,0 +1,80 @@ +--- +id: version-5.1.1-provider +title: Provider +sidebar_label: Provider +original_id: provider +--- + +# `` + +## Overview + +The `` makes the Redux `store` available to any nested components that have been wrapped in the `connect()` function. + +Since any React component in a React-Redux app can be connected, most applications will render a `` at the top level, with the entire app’s component tree inside of it. + +Normally, you can’t use a connected component unless it is nested inside of a `` . + +Note: If you really need to, you can manually pass `store` as a prop to a connected component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +### Props + +`store` (Redux Store) +The single Redux `store` in your application. + +`children` (ReactElement) +The root of your component hierarchy. + + +### Example Usage + +In the example below, the `` component is our root-level component. This means it’s at the very top of our component hierarchy. + +**Vanilla React Example** + +```jsx + import React from 'react'; + import ReactDOM from 'react-dom'; + import { Provider } from 'react-redux'; + + import { App } from './App'; + import createStore from './createReduxStore'; + + const store = createStore(); + + ReactDOM.render( + + + , + document.getElementById('root') + ) +``` + + +**Usage with React Router** + +```jsx + import React from 'react'; + import ReactDOM from 'react-dom'; + import { Provider } from 'react-redux'; + import { Router, Route } from 'react-router-dom'; + + import { App } from './App'; + import { Foo } from './Foo'; + import { Bar } from './Bar'; + import createStore from './createReduxStore'; + + const store = createStore(); + + ReactDOM.render( + + + + + + + + , + document.getElementById('root') + ) +``` diff --git a/website/versioned_docs/version-5.1.1/api/api.md b/website/versioned_docs/version-5.1.1/api/api.md new file mode 100644 index 000000000..4440b6950 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/api/api.md @@ -0,0 +1,492 @@ +--- +id: version-5.1.1-api +title: Api +sidebar_label: API +hide_title: true +original_id: api +--- + +# API + + +## Provider + +Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. + +If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +### Props + +* `store` (*[Redux Store](https://redux.js.org/api-reference/store)*): The single Redux store in your application. +* `children` (*ReactElement*) The root of your component hierarchy. + +### Example + +#### Vanilla React + +```jsx +ReactDOM.render( + + + , + rootEl +) +``` + +#### React Router + +```jsx +ReactDOM.render( + + + + + + + + , + document.getElementById('root') +) +``` + + +## connect + +``` +connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) +``` + +Connects a React component to a Redux store. `connect` is a facade around `connectAdvanced`, providing a convenient API for the most common use cases. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* [`mapStateToProps(state, [ownProps]): stateProps`] \(*Function*): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into the component’s props. If you don't want to subscribe to store updates, pass `null` or `undefined` in place of `mapStateToProps`. + + If your `mapStateToProps` function is declared as taking two parameters, it will be called with the store state as the first parameter and the props passed to the connected component as the second parameter, and will also be re-invoked whenever the connected component receives new props as determined by shallow equality comparisons. (The second parameter is normally referred to as `ownProps` by convention.) + + >Note: in advanced scenarios where you need more control over the rendering performance, `mapStateToProps()` can also return a function. In this case, *that* function will be used as `mapStateToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + + >The `mapStateToProps` function's first argument is the entire Redux store’s state and it returns an object to be passed as props. It is often called a **selector**. Use [reselect](https://github.com/reduxjs/reselect) to efficiently compose selectors and [compute derived data](https://redux.js.org/recipes/computing-derived-data). + +* [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(*Object* or *Function*): If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a `dispatch` call so they may be invoked directly, will be merged into the component’s props. + + If a function is passed, it will be given `dispatch` as the first parameter. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](https://redux.js.org/api-reference/bindactioncreators) helper from Redux.) + + If your `mapDispatchToProps` function is declared as taking two parameters, it will be called with `dispatch` as the first parameter and the props passed to the connected component as the second parameter, and will be re-invoked whenever the connected component receives new props. (The second parameter is normally referred to as `ownProps` by convention.) + + If you do not supply your own `mapDispatchToProps` function or object full of action creators, the default `mapDispatchToProps` implementation just injects `dispatch` into your component’s props. + + >Note: in advanced scenarios where you need more control over the rendering performance, `mapDispatchToProps()` can also return a function. In this case, *that* function will be used as `mapDispatchToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + +* [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(*Function*): If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, dispatchProps)` is used by default. + +* [`options`] *(Object)* If specified, further customizes the behavior of the connector. In addition to the options passable to `connectAdvanced()` (see those below), `connect()` accepts these additional options: + * [`pure`] *(Boolean)*: If true, `connect()` will avoid re-renders and calls to `mapStateToProps`, `mapDispatchToProps`, and `mergeProps` if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: `true` + * [`areStatesEqual`] *(Function)*: When pure, compares incoming store state to its previous value. Default value: `strictEqual (===)` + * [`areOwnPropsEqual`] *(Function)*: When pure, compares incoming props to its previous value. Default value: `shallowEqual` + * [`areStatePropsEqual`] *(Function)*: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` + * [`areMergedPropsEqual`] *(Function)*: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` + * [`storeKey`] *(String)*: The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + +#### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps + +> Note: `ownProps` **is not passed** to `mapStateToProps` and `mapDispatchToProps` if the formal definition of the function contains one mandatory parameter (function has length 1). For example, functions defined like below won't receive `ownProps` as the second argument. + +```js +function mapStateToProps(state) { + console.log(state); // state + console.log(arguments[1]); // undefined +} +``` +```js +const mapStateToProps = (state, ownProps = {}) => { + console.log(state); // state + console.log(ownProps); // {} +} +``` + +Functions with no mandatory parameters or two parameters **will receive** `ownProps`. +```js +const mapStateToProps = (state, ownProps) => { + console.log(state); // state + console.log(ownProps); // ownProps +} +``` +```js +function mapStateToProps() { + console.log(arguments[0]); // state + console.log(arguments[1]); // ownProps +} +``` +```js +const mapStateToProps = (...args) => { + console.log(args[0]); // state + console.log(args[1]); // ownProps +} +``` + +#### Optimizing connect when options.pure is true + +When `options.pure` is true, `connect` performs several equality checks that are used to avoid unnecessary calls to `mapStateToProps`, `mapDispatchToProps`, `mergeProps`, and ultimately to `render`. These include `areStatesEqual`, `areOwnPropsEqual`, `areStatePropsEqual`, and `areMergedPropsEqual`. While the defaults are probably appropriate 99% of the time, you may wish to override them with custom implementations for performance or other reasons. Here are several examples: + +* You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. For example: `areStatesEqual: (next, prev) => prev.entities.todos === next.entities.todos`; this would effectively ignore state changes for everything but that slice of state. + +* You may wish to override `areStatesEqual` to always return false (`areStatesEqual: () => false`) if you have impure reducers that mutate your store state. (This would likely impact the other equality checks as well, depending on your `mapStateToProps` function.) + +* You may wish to override `areOwnPropsEqual` as a way to whitelist incoming props. You'd also have to implement `mapStateToProps`, `mapDispatchToProps` and `mergeProps` to also whitelist props. (It may be simpler to achieve this other ways, for example by using [recompose's mapProps](https://github.com/acdlite/recompose/blob/master/docs/API.md#mapprops).) + +* You may wish to override `areStatePropsEqual` to use `strictEqual` if your `mapStateToProps` uses a memoized selector that will only return a new object if a relevant prop has changed. This would be a very slight performance improvement, since would avoid extra equality checks on individual props each time `mapStateToProps` is called. + +* You may wish to override `areMergedPropsEqual` to implement a `deepEqual` if your selectors produce complex props. ex: nested objects, new arrays, etc. (The deep equal check should be faster than just re-rendering.) + +### Returns + +A higher-order React component class that passes state and action creators into your component derived from the supplied arguments. This is created by `connectAdvanced`, and details of this higher-order component are covered there. + + +#### Examples + +#### Inject just `dispatch` and don't listen to store + +```js +export default connect()(TodoApp) +``` + +#### Inject all action creators (`addTodo`, `completeTodo`, ...) without subscribing to the store + +```js +import * as actionCreators from './actionCreators' + +export default connect(null, actionCreators)(TodoApp) +``` + +#### Inject `dispatch` and every field in the global state + +>Don’t do this! It kills any performance optimizations because `TodoApp` will rerender after every state change. +>It’s better to have more granular `connect()` on several components in your view hierarchy that each only +>listen to a relevant slice of the state. + +```js +export default connect(state => state)(TodoApp) +``` + +#### Inject `dispatch` and `todos` + +```js +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps)(TodoApp) +``` + +#### Inject `todos` and all action creators + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps, actionCreators)(TodoApp) +``` + +#### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) as `actions` + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { actions: bindActionCreators(actionCreators, dispatch) } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` and a specific action creator (`addTodo`) + +```js +import { addTodo } from './actionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators({ addTodo }, dispatch) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` and specific action creators (`addTodo` and `deleteTodo`) with shorthand syntax + +```js +import { addTodo, deleteTodo } from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +const mapDispatchToProps = { + addTodo, + deleteTodo +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, todoActionCreators as `todoActions`, and counterActionCreators as `counterActions` + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { + todoActions: bindActionCreators(todoActionCreators, dispatch), + counterActions: bindActionCreators(counterActionCreators, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, and todoActionCreators and counterActionCreators together as `actions` + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, and all todoActionCreators and counterActionCreators directly as props + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` of a specific user depending on props + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state, ownProps) { + return { todos: state.todos[ownProps.userId] } +} + +export default connect(mapStateToProps)(TodoApp) +``` + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mergeProps(stateProps, dispatchProps, ownProps) { + return Object.assign({}, ownProps, { + todos: stateProps.todos[ownProps.userId], + addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text) + }) +} + +export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp) +``` + +#### Factory functions + +Factory functions can be used for performance optimizations + +```js +import { addTodo } from './actionCreators' + +function mapStateToPropsFactory(initialState, initialProps) { + const getSomeProperty= createSelector(...); + const anotherProperty = 200 + initialState[initialProps.another]; + return function(state){ + return { + anotherProperty, + someProperty: getSomeProperty(state), + todos: state.todos + } + } +} + +function mapDispatchToPropsFactory(initialState, initialProps) { + function goToSomeLink(){ + initialProps.history.push('some/link'); + } + return function(dispatch){ + return { + addTodo + } + } +} + + +export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp) +``` + +## connectAdvanced + +```js +connectAdvanced(selectorFactory, [connectOptions]) +``` + +Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(*Function*): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. + +* [`connectOptions`] *(Object)* If specified, further customizes the behavior of the connector. + + * [`getDisplayName`] *(Function)*: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` + + * [`methodName`] *(String)*: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` + + * [`renderCountProp`] *(String)*: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` + + * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` + + * [`storeKey`] *(String)*: the key of props/context to get the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + + * [`withRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` + + * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. + + + +### Returns + +A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. + +#### Static Properties + +* `WrappedComponent` *(Component)*: The original component class passed to `connectAdvanced(...)(Component)`. + +#### Static Methods + +All the original static methods of the component are hoisted. + +#### Instance Methods + +##### `getWrappedInstance(): ReactComponent` + +Returns the wrapped component instance. Only available if you pass `{ withRef: true }` as part of the `options` argument. + +### Remarks + +* Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. + +* `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. + + +#### Examples + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function selectorFactory(dispatch) { + let ownProps = {} + let result = {} + const actions = bindActionCreators(actionCreators, dispatch) + const addTodo = (text) => actions.addTodo(ownProps.userId, text) + return (nextState, nextOwnProps) => { + const todos = nextState.todos[nextOwnProps.userId] + const nextResult = { ...nextOwnProps, todos, addTodo } + ownProps = nextOwnProps + if (!shallowEqual(result, nextResult)) result = nextResult + return result + } +} +export default connectAdvanced(selectorFactory)(TodoApp) +``` + +## createProvider + +```js +createProvider([storeKey]) +``` + +Creates a new `` which will set the Redux Store on the passed key of the context. You probably only need this if you are in the inadvisable position of having multiple stores. You will also need to pass the same `storeKey` to the `options` argument of [`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) + +### Arguments + +* [`storeKey`] (*String*): The key of the context on which to set the store. Default value: `'store'` + +### Examples +Before creating multiple stores, please go through this FAQ: [Can or should I create multiple stores?](http://redux.js.org/docs/faq/StoreSetup.html#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) + +```js +import {connect, createProvider} from 'react-redux' + +const STORE_KEY = 'componentStore' + +export const Provider = createProvider(STORE_KEY) + +function connectExtended( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options = {} +) { + options.storeKey = STORE_KEY + return connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options + ) +} + +export {connectExtended as connect} +``` +Now you can import the above `Provider` and `connect` and use them. diff --git a/website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md b/website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md new file mode 100644 index 000000000..b82bd8658 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md @@ -0,0 +1,459 @@ +--- +id: version-5.1.1-basic-tutorial +title: Basic Tutorial +hide_title: true +sidebar_label: Basic Tutorial +original_id: basic-tutorial +--- + +# Basic Tutorial + +To see how to use React-Redux in practice, we’ll show a step-by-step example by creating a todo list app. + +## A Todo List Example + +**Jump to** + +- 🤞 [Just show me the code](https://codesandbox.io/s/9on71rvnyo) +- 👆 [Providing the store](#providing-the-store) +- ✌️ [Connecting the Component](#connecting-the-components) + +**The React UI Components** + +We have implemented our React UI components as follows: + +- `TodoApp` is the entry component for our app. It renders the header, the `AddTodo`, `TodoList`, and `VisibilityFilters` components. +- `AddTodo` is the component that allows a user to input a todo item and add to the list upon clicking its “Add Todo” button: + - It uses a controlled input that sets state upon `onChange`. + - When the user clicks on the “Add Todo” button, it dispatches the action (that we will provide using React-Redux) to add the todo to the store. +- `TodoList` is the component that renders the list of todos: + - It renders the filtered list of todos when one of the `VisibilityFilters` is selected. +- `Todo` is the component that renders a single todo item: + - It renders the todo content, and shows that a todo is completed by crossing it out. + - It dispatches the action to toggle the todo's complete status upon `onClick`. +- `VisibilityFilters` renders a simple set of filters: _all_, _completed_, and _incomplete._ Clicking on each one of them filters the todos: + - It accepts an `activeFilter` prop from the parent that indicates which filter is currently selected by the user. An active filter is rendered with an underscore. + - It dispatches the `setFilter` action to update the selected filter. +- `constants` holds the constants data for our app. +- And finally `index` renders our app to the DOM. + +
+ +**The Redux Store** + +The Redux portion of the application has been set up using the [patterns recommended in the Redux docs](https://redux.js.org): + +- Store + - `todos`: A normalized reducer of todos. It contains a `byIds` map of all todos and a `allIds` that contains the list of all ids. + - `visibilityFilters`: A simple string `all`, `completed`, or `incomplete`. +- Action Creators + - `addTodo` creates the action to add todos. It takes a single string variable `content` and returns an `ADD_TODO` action with `payload` containing a self-incremented `id` and `content` + - `toggleTodo` creates the action to toggle todos. It takes a single number variable `id` and returns a `TOGGLE_TODO` action with `payload` containing `id` only + - `setFilter` creates the action to set the app’s active filter. It takes a single string variable `filter` and returns a `SET_FILTER` action with `payload` containing the `filter` itself +- Reducers + - The `todos` reducer + - Appends the `id` to its `allIds` field and sets the todo within its `byIds` field upon receiving the `ADD_TODO` action + - Toggles the `completed` field for the todo upon receiving the `TOGGLE_TODO` action + - The `visibilityFilters` reducer sets its slice of store to the new filter it receives from the `SET_FILTER` action payload +- Action Types + - We use a file `actionTypes.js` to hold the constants of action types to be reused +- Selectors + - `getTodoList` returns the `allIds` list from the `todos` store + - `getTodoById` finds the todo in the store given by `id` + - `getTodos` is slightly more complex. It takes all the `id`s from `allIds`, finds each todo in `byIds`, and returns the final array of todos + - `getTodosByVisibilityFilter` filters the todos according to the visibility filter + +You may check out [this CodeSandbox](https://codesandbox.io/s/6vwyqrpqk3) for the source code of the UI components and the unconnected Redux store described above. + +
+ +We will now show how to connect this store to our app using React-Redux. + +### Providing the Store + +First we need to make the `store` available to our app. To do this, we wrap our app with the `` API provided by React-Redux. + +```jsx +// index.js +import React from "react"; +import ReactDOM from "react-dom"; +import TodoApp from "./TodoApp"; + +import { Provider } from "react-redux"; +import store from "./redux/store"; + +const rootElement = document.getElementById("root"); +ReactDOM.render( + + + , + rootElement +); +``` + +Notice how our `` is now wrapped with the `` with `store` passed in as a prop. + +![](https://i.imgur.com/LV0XvwA.png) + +### Connecting the Components + +React-Redux provides a `connect` function for you to read values from the Redux store (and re-read the values when the store updates). + +The `connect` function takes two arguments, both optional: + +- `mapStateToProps`: called every time the store state changes. It receives the entire store state, and should return an object of data this component needs. + +- `mapDispatchToProps`: this parameter can either be a function, or an object. + - If it’s a function, it will be called once on component creation. It will receive `dispatch` as an argument, and should return an object full of functions that use `dispatch` to dispatch actions. + - If it’s an object full of action creators, each action creator will be turned into a prop function that automatically dispatches its action when called. **Note**: We recommend using this “object shorthand” form. + +Normally, you’ll call `connect` in this way: + +```js +const mapStateToProps = (state, ownProps) => ({ + // ... computed data from state and optionally ownProps +}); + +const mapDispatchToProps = { + // ... normally is an object full of action creators +}; + +// `connect` returns a new function that accepts the component to wrap: +const connectToStore = connect( + mapStateToProps, + mapDispatchToProps +); +// and that function returns the connected, wrapper component: +const ConnectedComponent = connectToStore(Component); + +// We normally do both in one step, like this: +connect( + mapStateToProps, + mapDispatchToProps +)(Component); +``` + +Let’s work on `` first. It needs to trigger changes to the `store` to add new todos. Therefore, it needs to be able to `dispatch` actions to the store. Here’s how we do it. + +Our `addTodo` action creator looks like this: + +```js +// redux/actions.js +import { ADD_TODO } from "./actionTypes"; + +let nextTodoId = 0; +export const addTodo = content => ({ + type: ADD_TODO, + payload: { + id: ++nextTodoId, + content + } +}); + +// ... other actions +``` + +By passing it to `connect`, our component receives it as a prop, and it will automatically dispatch the action when it’s called. + +```js +// components/AddTodo.js + +// ... other imports +import { connect } from "react-redux"; +import { addTodo } from "../redux/actions"; + +class AddTodo extends React.Component { + // ... component implementation +} + +export default connect( + null, + { addTodo } +)(AddTodo); +``` + +Notice now that `` is wrapped with a parent component called ``. Meanwhile, `` now gains one prop: the `addTodo` action. + +![](https://i.imgur.com/u6aXbwl.png) + +We also need to implement the `handleAddTodo` function to let it dispatch the `addTodo` action and reset the input + +```jsx +// components/AddTodo.js + +import React from "react"; +import { connect } from "react-redux"; +import { addTodo } from "../redux/actions"; + +class AddTodo extends React.Component { + // ... + + handleAddTodo = () => { + // dispatches actions to add todo + this.props.addTodo(this.state.input); + + // sets state back to empty string + this.setState({ input: "" }); + }; + + render() { + return ( +
+ this.updateInput(e.target.value)} + value={this.state.input} + /> + +
+ ); + } +} + +export default connect( + null, + { addTodo } +)(AddTodo); +``` + +Now our `` is connected to the store. When we add a todo it would dispatch an action to change the store. We are not seeing it in the app because the other components are not connected yet. If you have the Redux DevTools Extension hooked up, you should see the action being dispatched: + +![](https://i.imgur.com/kHvkqhI.png) + +You should also see that the store has changed accordingly: + +![](https://i.imgur.com/yx27RVC.png) + +The `` component is responsible for rendering the list of todos. Therefore, it needs to read data from the store. We enable it by calling `connect` with the `mapStateToProps` parameter, a function describing which part of the data we need from the store. + +Our `` component takes the todo item as props. We have this information from the `byIds` field of the `todos`. However, we also need the information from the `allIds` field of the store indicating which todos and in what order they should be rendered. Our `mapStateToProps` function may look like this: + +```js +// components/TodoList.js + +// ...other imports +import { connect } from "react-redux"; + +const TodoList = // ... UI component implementation + +const mapStateToProps = state => { + const { byIds, allIds } = state.todos || {}; + const todos = + allIds && allIds.length + ? allIds.map(id => (byIds ? { ...byIds[id], id } : null)) + : null; + return { todos }; +}; + +export default connect(mapStateToProps)(TodoList); +``` + +Luckily we have a selector that does exactly this. We may simply import the selector and use it here. + +```js +// redux/selectors.js + +export const getTodosState = store => store.todos; + +export const getTodoList = store => + getTodosState(store) ? getTodosState(store).allIds : []; + +export const getTodoById = (store, id) => + getTodosState(store) ? { ...getTodosState(store).byIds[id], id } : {}; + +export const getTodos = store => + getTodoList(store).map(id => getTodoById(store, id)); +``` + +```js +// components/TodoList.js + +// ...other imports +import { connect } from "react-redux"; +import { getTodos } from "../redux/selectors"; + +const TodoList = // ... UI component implementation + +export default connect(state => ({ todos: getTodos(state) }))(TodoList); +``` + +We recommend encapsulating any complex lookups or computations of data in selector functions. In addition, you can further optimize the performance by using [Reselect](https://github.com/reduxjs/reselect) to write “memoized” selectors that can skip unnecessary work. (See [the Redux docs page on Computing Derived Data](https://redux.js.org/recipes/computingderiveddata#sharing-selectors-across-multiple-components) and the blog post [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) for more information on why and how to use selector functions.) + +Now that our `` is connected to the store. It should receive the list of todos, map over them, and pass each todo to the `` component. `` will in turn render them to the screen. Now try adding a todo. It should come up on our todo list! + +![](https://i.imgur.com/N68xvrG.png) + +We will connect more components. Before we do this, let’s pause and learn a bit more about `connect` first. + +### Common ways of calling `connect` + +Depending on what kind of components you are working with, there are different ways of calling `connect` , with the most common ones summarized as below: + +| | Do Not Subscribe to the Store | Subscribe to the Store | +| ----------------------------- | ---------------------------------------------- | --------------------------------------------------------- | +| Do Not Inject Action Creators | `connect()(Component)` | `connect(mapStateToProps)(Component)` | +| Inject Action Creators | `connect(null, mapDispatchToProps)(Component)` | `connect(mapStateToProps, mapDispatchToProps)(Component)` | + +#### Do not subscribe to the store and do not inject action creators + +If you call `connect` without providing any arguments, your component will: + +- _not_ re-render when the store changes +- receive `props.dispatch` that you may use to manually dispatch action + +```js +// ... Component +export default connect()(Component); // Component will receive `dispatch` (just like our !) +``` + +#### Subscribe to the store and do not inject action creators + +If you call `connect` with only `mapStateToProps`, your component will: + +- subscribe to the values that `mapStateToProps` extracts from the store, and re-render only when those values have changed +- receive `props.dispatch` that you may use to manually dispatch action + +```js +// ... Component +const mapStateToProps = state => state.partOfState; +export default connect(mapStateToProps)(Component); +``` + +#### Do not subscribe to the store and inject action creators + +If you call `connect` with only `mapDispatchToProps`, your component will: + +- _not_ re-render when the store changes +- receive each of the action creators you inject with `mapDispatchToProps` as props and automatically dispatch the actions upon being called + +```js +import { addTodo } from "./actionCreators"; +// ... Component +export default connect( + null, + { addTodo } +)(Component); +``` + +#### Subscribe to the store and inject action creators + +If you call `connect` with both `mapStateToProps` and `mapDispatchToProps`, your component will: + +- subscribe to the values that `mapStateToProps` extracts from the store, and re-render only when those values have changed +- receive all of the action creators you inject with `mapDispatchToProps` as props and automatically dispatch the actions upon being called. + +```js +import * as actionCreators from "./actionCreators"; +// ... Component +const mapStateToProps = state => state.partOfState; +export default connect( + mapStateToProps, + actionCreators +)(Component); +``` + +These four cases cover the most basic usages of `connect`. To read more about `connect`, continue reading our [API section](./api.md) that explains it in more detail. + + + +--- + +Now let’s connect the rest of our ``. + +How should we implement the interaction of toggling todos? A keen reader might already have an answer. If you have your environment set up and have followed through up until this point, now is a good time to leave it aside and implement the feature by yourself. There would be no surprise that we connect our `` to dispatch `toggleTodo` in a similar way: + +```js +// components/Todo.js + +// ... other imports +import { connect } from "react-redux"; +import { toggleTodo } from "../redux/actions"; + +const Todo = // ... component implementation + +export default connect( + null, + { toggleTodo } +)(Todo); +``` + +Now our todo’s can be toggled complete. We’re almost there! + +![](https://i.imgur.com/4UBXYtj.png) + +Finally, let’s implement our `VisibilityFilters` feature. + +The `` component needs to be able to read from the store which filter is currently active, and dispatch actions to the store. Therefore, we need to pass both a `mapStateToProps` and `mapDispatchToProps`. The `mapStateToProps` here can be a simple accessor of the `visibilityFilter` state. And the `mapDispatchToProps` will contain the `setFilter` action creator. + +```js +// components/VisibilityFilters.js + +// ... other imports +import { connect } from "react-redux"; +import { setFilter } from "../redux/actions"; + +const VisibilityFilters = // ... component implementation + +const mapStateToProps = state => { + return { activeFilter: state.visibilityFilter }; +}; +export default connect( + mapStateToProps, + { setFilter } +)(VisibilityFilters); +``` + +Meanwhile, we also need to update our `` component to filter todos according to the active filter. Previously the `mapStateToProps` we passed to the `` `connect` function call was simply the selector that selects the whole list of todos. Let’s write another selector to help filtering todos by their status. + +```js +// redux/selectors.js + +// ... other selectors +export const getTodosByVisibilityFilter = (store, visibilityFilter) => { + const allTodos = getTodos(store); + switch (visibilityFilter) { + case VISIBILITY_FILTERS.COMPLETED: + return allTodos.filter(todo => todo.completed); + case VISIBILITY_FILTERS.INCOMPLETE: + return allTodos.filter(todo => !todo.completed); + case VISIBILITY_FILTERS.ALL: + default: + return allTodos; + } +}; +``` + +And connecting to the store with the help of the selector: + +```js +// components/TodoList.js + +// ... + +const mapStateToProps = state => { + const { visibilityFilter } = state; + const todos = getTodosByVisibilityFilter(state, visibilityFilter); + return { todos }; +}; + +export default connect(mapStateToProps)(TodoList); +``` + +Now we've finished a very simple example of a todo app with React-Redux. All our components are connected! Isn't that nice? 🎉🎊 + +![](https://i.imgur.com/ONqer2R.png) + +## Links + +- [Usage with React](https://redux.js.org/basics/usagewithreact) +- [Using the React-Redux Bindings](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/react-redux.html) +- [Higher Order Components in Depth](https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e) +- [Computing Derived Data](https://redux.js.org/recipes/computingderiveddata#sharing-selectors-across-multiple-components) +- [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) + +## Get More Help + +- [Reactiflux](https://www.reactiflux.com) Redux channel +- [StackOverflow](https://stackoverflow.com/questions/tagged/react-redux) +- [GitHub Issues](https://github.com/reduxjs/react-redux/issues/) diff --git a/website/versioned_docs/version-5.1.1/introduction/quick-start.md b/website/versioned_docs/version-5.1.1/introduction/quick-start.md new file mode 100644 index 000000000..fe302e5f9 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/introduction/quick-start.md @@ -0,0 +1,71 @@ +--- +id: version-5.1.1-quick-start +title: Quick Start +hide_title: true +sidebar_label: Quick Start +original_id: quick-start +--- + +# Quick Start + +[React-Redux](https://github.com/reduxjs/react-redux) is the official [React](https://reactjs.org/) binding for [Redux](https://redux.js.org/). It lets your React components read data from a Redux store, and dispatch actions to the store to update data. + +## Installation + +To use React-Redux with your React app: + +```bash +npm install --save react-redux +``` + +or + +```bash +yarn add react-redux +``` + +## `Provider` and `connect` + +React-Redux provides ``, which makes the Redux store available to the rest of your app: + +```js +import React from "react"; +import ReactDOM from "react-dom"; + +import { Provider } from "react-redux"; +import store from "./store"; + +import App from "./App"; + +const rootElement = document.getElementById("root"); +ReactDOM.render( + + + , + rootElement +); +``` + +React-Redux provides a `connect` function for you to connect your component to the store. + +Normally, you’ll call `connect` in this way: + +```js +import { connect } from "react-redux"; +import { increment, decrement, reset } from "./actionCreators"; + +// const Counter = ... + +const mapStateToProps = (state /*, ownProps*/) => { + return { + counter: state.counter + }; +}; + +const mapDispatchToProps = { increment, decrement, reset }; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(Counter); +``` diff --git a/website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md b/website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md new file mode 100644 index 000000000..917205616 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md @@ -0,0 +1,98 @@ +--- +id: version-5.1.1-why-use-react-redux +title: Why Use React-Redux? +hide_title: true +sidebar_label: Why Use React-Redux? +original_id: why-use-react-redux +--- + +# Why Use React-Redux? + +Redux itself is a standalone library that can be used with any UI layer or framework, including React, Angular, Vue, Ember, and vanilla JS. Although Redux and React are commonly used together, they are independent of each other. + +If you are using Redux with any kind of UI framework, you will normally use a "UI binding" library to tie Redux together with your UI framework, rather than directly interacting with the store from your UI code. + +**React-Redux is the official Redux UI binding library for React**. If you are using Redux and React together, you should also use React-Redux to bind these two libraries. + +To understand why you should use React-Redux, it may help to understand what a "UI binding library" does. + +> **Note**: If you have questions about whether you should use Redux in general, please see these articles for discussion of when and why you might want to use Redux, and how it's intended to be used: +> +> - [Redux docs: Motivation](https://redux.js.org/introduction/motivation) +> - [Redux docs: FAQ - When should I use Redux?](https://redux.js.org/faq/general#when-should-i-use-redux) +> - [You Might Not Need Redux](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367) +> - [Idiomatic Redux: The Tao of Redux, Part 1 - Implementation and Intent](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/) + + +## Integrating Redux with a UI + +Using Redux with _any_ UI layer requires [the same consistent set of steps](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html#/4): + +1. Create a Redux store +2. Subscribe to updates +3. Inside the subscription callback: + 1. Get the current store state + 2. Extract the data needed by this piece of UI + 3. Update the UI with the data +4. If necessary, render the UI with initial state +5. Respond to UI inputs by dispatching Redux actions + +While it is possible to write this logic by hand, doing so would become very repetitive. In addition, optimizing UI performance would require complicated logic. + +The process of subscribing to the store, checking for updated data, and triggering a re-render can be made more generic and reusable. **A UI binding library like React-Redux handles the store interaction logic, so you don't have to write that code yourself.** + + +## Reasons to Use React-Redux + +### It is the Official Redux UI Bindings for React + +While Redux can be used with any UI layer, it was originally designed and intended for use with React. There are [UI binding layers for many other frameworks](https://redux.js.org/introduction/ecosystem#library-integration-and-bindings), but React-Redux is maintained directly by the Redux team. + +As the offical Redux binding for React, React-Redux is kept up-to-date with any API changes from either library, to ensure that your React components behave as expected. Its intended usage adopts the design principles of React - writing declarative components. + + +### It Encourages Good React Architecture + +React components are a lot like functions. While it's possible to write all your code in a single function, it's usually better to split that logic into smaller functions that each handle a specific task, making them easier to understand. + +Similarly, while you can write large React components that handle many different tasks, it's usually better to split up components based on responsibilities. In particular, it is common to have "container" components that are responsible for collecting and managing some kind of data, and "presentational" components that simply display UI based on whatever data they've received as props. + +**The React-Redux `connect` function generates "container" wrapper components that handle the process of interacting with the store for you**. That way, your own components can focus on other tasks, whether it be collecting other data, or just displaying a piece of the UI. In addition, **`connect` abstracts away the question of _which_ store is being used, making your own components more reusable**. + +As a general architectural principle, **we want to keep our own components "unaware" of Redux**. They should simply receive data and functions as props, just like any other React component. This ultimately makes it easier to test and reuse your own components. + + +### It Implements Performance Optimizations For You + +React is generally fast, but by default any updates to a component will cause React to re-render all of the components inside that part of the component tree. This does require work, and if the data for a given component hasn't changed, then re-rendering is likely some wasted effort because the requested UI output would be the same. + +If performance is a concern, the best way to improve performance is to skip unnecessary re-renders, so that components only re-render when their data has actually changed. **React-Redux implements many performance optimizations internally, so that your own component only re-renders when it actually needs to.** + +In addition, by connecting multiple components in your React component tree, you can ensure that each connected component only extracts the specific pieces of data from the store state that are needed by that component. This means that your own component will need to re-render less often, because most of the time those specific pieces of data haven't changed. + + +### Community Support + +As the official binding library for React and Redux, React-Redux has a large community of users. This makes it easier to ask for help, learn about best practices, use libraries that build on top of React-Redux, and reuse your knowledge across different applications. + + + +## Links and References + + +### Understanding React-Redux + +- [Idiomatic Redux: The History and Implementation of React-Redux](https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/) +- [`connect.js` Explained](https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e) +- [Redux Fundamentals workshop slides](https://blog.isquaredsoftware.com/2018/06/redux-fundamentals-workshop-slides/) + - [UI Layer Integration](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html) + - [Using React-Redux](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/react-redux.html) + + +### Community Resources + +- Discord channel: [#redux on Reactiflux](https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e) ([Reactiflux invite link](https://reactiflux.com)) +- Stack Overflow topics: [Redux](https://stackoverflow.com/questions/tagged/redux), [React-Redux](https://stackoverflow.com/questions/tagged/redux) +- Reddit: [/r/reactjs](https://www.reddit.com/r/reactjs/), [/r/reduxjs](https://www.reddit.com/r/reduxjs/) +- Github issues (bug reports and feature requests): https://github.com/reduxjs/react-redux/issues +- Tutorials, articles, and further resources: [React/Redux Links](https://www.reddit.com/r/reduxjs/) \ No newline at end of file diff --git a/website/versioned_docs/version-5.1.1/troubleshooting.md b/website/versioned_docs/version-5.1.1/troubleshooting.md new file mode 100644 index 000000000..950252bc4 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/troubleshooting.md @@ -0,0 +1,88 @@ +--- +id: version-5.1.1-troubleshooting +title: Troubleshooting +sidebar_label: Troubleshooting +hide_title: true +original_id: troubleshooting +--- + +## Troubleshooting + +Make sure to check out [Troubleshooting Redux](http://redux.js.org/docs/Troubleshooting.html) first. + +### I'm getting the following alert: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead. +This warning is shown when using react 15.5.*. Basically, now it's just a warning, but in react16 the application might break. the PropTypes should now be imported from 'prop-types' package, and not from the react package. + +Update to the latest version of react-redux. + +### My views aren’t updating! + +See the link above. +In short, + +* Reducers should never mutate state, they must return new objects, or React Redux won’t see the updates. +* Make sure you either bind action creators with the `mapDispatchToProps` argument to `connect()` or with the `bindActionCreators()` method, or that you manually call `dispatch()`. Just calling your `MyActionCreators.addTodo()` function won’t work because it just *returns* an action, but does not *dispatch* it. + +### My views aren’t updating on route change with React Router 0.13 + +If you’re using React Router 0.13, you might [bump into this problem](https://github.com/reduxjs/react-redux/issues/43). The solution is simple: whenever you use `` or the `Handler` provided by `Router.run`, pass the router state to it. + +Root view: + +```jsx +Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { // note "routerState" here + ReactDOM.render( + + {/* note "routerState" here */} + + , + document.getElementById('root') + ) +}) +``` + +Nested view: + +```js +render() { + // Keep passing it down + return +} +``` + +Conveniently, this gives your components access to the router state! +You can also upgrade to React Router 1.0 which shouldn’t have this problem. (Let us know if it does!) + +### My views aren’t updating when something changes outside of Redux + +If your views depend on global state or [React “context”](http://facebook.github.io/react/docs/context.html), you might find that views decorated with `connect()` will fail to update. + +>This is because `connect()` implements [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) by default, assuming that your component will produce the same results given the same props and state. This is a similar concept to React’s [PureRenderMixin](https://facebook.github.io/react/docs/pure-render-mixin.html). + +The _best_ solution to this is to make sure that your components are pure and pass any external state to them via props. This will ensure that your views do not re-render unless they actually need to re-render and will greatly speed up your application. + +If that’s not practical for whatever reason (for example, if you’re using a library that depends heavily on React context), you may pass the `pure: false` option to `connect()`: + +```js +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps, null, null, { + pure: false +})(TodoApp) +``` + +This will remove the assumption that `TodoApp` is pure and cause it to update whenever its parent component renders. Note that this will make your application less performant, so only do this if you have no other option. + +### Could not find "store" in either the context or props + +If you have context issues, + +1. [Make sure you don’t have a duplicate instance of React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375) on the page. +2. Make sure you didn’t forget to wrap your root or some other ancestor component in [``](#provider-store). +3. Make sure you’re running the latest versions of React and React Redux. + +### Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you’re trying to add a ref to a component that doesn’t have an owner + +If you’re using React for web, this usually means you have a [duplicate React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375). Follow the linked instructions to fix this. diff --git a/website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md b/website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md new file mode 100644 index 000000000..31aaa0a08 --- /dev/null +++ b/website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md @@ -0,0 +1,407 @@ +--- +id: version-5.1.1-connect-mapdispatch +title: Connect: Dispatching Actions with mapDispatchToProps +hide_title: true +sidebar_label: Connect: Dispatching Actions with mapDispatchToProps +original_id: connect-mapdispatch +--- + +# Connect: Dispatching Actions with `mapDispatchToProps` + +As the second argument passed in to `connect`, `mapDispatchToProps` is used for dispatching actions to the store. + +`dispatch` is a function of the Redux store. You call `store.dispatch` to dispatch an action. +This is the only way to trigger a state change. + +With React-Redux, your components never access the store directly - `connect` does it for you. +React-Redux gives you two ways to let components dispatch actions: + +- By default, a connected component receives `props.dispatch` and can dispatch actions itself. +- `connect` can accept an argument called `mapDispatchToProps`, which lets you create functions that dispatch when called, and pass those functions as props to your component. + +The `mapDispatchToProps` functions are normally referred to as `mapDispatch` for short, but the actual variable name used can be whatever you want. + +## Approaches for Dispatching + +### Default: `dispatch` as a Prop + +If you don't specify the second argument to `connect()`, your component will receive `dispatch` by default. For example: + +```js +connect()(MyComponent); +// which is equivalent with +connect( + null, + null +)(MyComponent); + +// or +connect(mapStateToProps /** no second argument */)(MyComponent); +``` + +Once you have connected your component in this way, your component receives `props.dispatch`. You may use it to dispatch actions to the store. + +```js +function Counter({ count, dispatch }) { + return ( +
+ + {count} + + +
+ ); +} +``` + +### Providing A `mapDispatchToProps` Parameter + +Providing a `mapDispatchToProps` allows you to specify which actions your component might need to dispatch. It lets you provide action dispatching functions as props. Therefore, instead of calling `props.dispatch(() => increment())`, you may call `props.increment()` directly. There are a few reasons why you might want to do that. + +#### More Declarative + +First, encapsulating the dispatch logic into function makes the implementation more declarative. +Dispatching an action and letting the Redux store handle the data flow is _how to_ implement the behavior, rather than _what_ it does. + +A good example would be dispatching an action when a button is clicked. Connecting the button directly probably doesn't make sense conceptually, and neither does having the button reference `dispatch`. + +```js +// button needs to be aware of "dispatch" + + {count} + + + + ); +} +``` + +(Full code of the Counter example is [in this CodeSandbox](https://codesandbox.io/s/yv6kqo1yw9)) + +### Defining the `mapDispatchToProps` Function with `bindActionCreators` + +Wrapping these functions by hand is tedious, so Redux provides a function to simplify that. + +> `bindActionCreators` turns an object whose values are [action creators](https://redux.js.org/glossary#action-creator), into an object with the same keys, but with every action creator wrapped into a [`dispatch`](https://redux.js.org/api/store#dispatch) call so they may be invoked directly. See [Redux Docs on `bindActionCreators`](http://redux.js.org/docs/api/bindActionCreators.html) + +`bindActionCreators` accepts two parameters: + +1. A **`function`** (an action creator) or an **`object`** (each field an action creator) +2. `dispatch` + +The wrapper functions generated by `bindActionCreators` will automatically forward all of their arguments, so you don't need to do that by hand. + +```js +import { bindActionCreators } from "redux"; + +const increment = () => ({ type: "INCREMENT" }); +const decrement = () => ({ type: "DECREMENT" }); +const reset = () => ({ type: "RESET" }); + +// binding an action creator +// returns (...args) => dispatch(increment(...args)) +const boundIncrement = bindActionCreators(increment, dispatch); + +// binding an object full of action creators +const boundActionCreators = bindActionCreators({ increment, decrement, reset }, dispatch); +// returns +// { +// increment: (...args) => dispatch(increment(...args)), +// decrement: (...args) => dispatch(decrement(...args)), +// reset: (...args) => dispatch(reset(...args)), +// } +``` + +To use `bindActionCreators` in our `mapDispatchToProps` function: + +```js +import { bindActionCreators } from "redux"; +// ... + +function mapDispatchToProps(dispatch) { + return bindActionCreators({ increment, decrement, reset }, dispatch); +} + +// component receives props.increment, props.decrement, props.reset +connect( + null, + mapDispatchToProps +)(Counter); +``` + +### Manually Injecting `dispatch` + +If the `mapDispatchToProps` argument is supplied, the component will no longer receive the default `dispatch`. You may bring it back by adding it manually to the return of your `mapDispatchToProps`, although most of the time you shouldn’t need to do this: + +```js +import { bindActionCreators } from "redux"; +// ... + +function mapDispatchToProps(dispatch) { + return { + dispatch, + ...bindActionCreators({ increment, decrement, reset }, dispatch) + }; +} +``` + +## Defining `mapDispatchToProps` As An Object + +You’ve seen that the setup for dispatching Redux actions in a React component follows a very similar process: define an action creator, wrap it in another function that looks like `(…args) => dispatch(actionCreator(…args))`, and pass that wrapper function as a prop to your component. + +Because this is so common, `connect` supports an “object shorthand” form for the `mapDispatchToProps` argument: if you pass an object full of action creators instead of a function, `connect` will automatically call `bindActionCreators` for you internally. + +**We recommend always using the “object shorthand” form of `mapDispatchToProps`, unless you have a specific reason to customize the dispatching behavior.** + +Note that: + +- Each field of the `mapDispatchToProps` object is assumed to be an action creator +- Your component will no longer receive `dispatch` as a prop + +```js +// React-Redux does this for you automatically: +dispatch => bindActionCreators(mapDispatchToProps, dispatch); +``` + +Therefore, our `mapDispatchToProps` can simply be: + +```js +const mapDispatchToProps = { + increment, + decrement, + reset +}; +``` + +Since the actual name of the variable is up to you, you might want to give it a name like `actionCreators`, or even define the object inline in the call to `connect`: + +```js +import {increment, decrement, reset} from "./counterActions"; + +const actionCreators = { + increment, + decrement, + reset +} + +export default connect(mapState, actionCreators)(Counter); + +// or +export default connect( + mapState, + { increment, decrement, reset } +)(Counter); +``` + +## Common Problems + +### Why is my component not receiving `dispatch`? + +Also known as + +```js +TypeError: this.props.dispatch is not a function +``` + +This is a common error that happens when you try to call `this.props.dispatch` , but `dispatch` is not injected to your component. + +`dispatch` is injected to your component _only_ when: + +**1. You do not provide `mapDispatchToProps`** + +The default `mapDispatchToProps` is simply `dispatch => ({ dispatch })`. If you do not provide `mapDispatchToProps`, `dispatch` will be provided as mentioned above. + +In another words, if you do: + +```js +// component receives `dispatch` +connect(mapStateToProps /** no second argument*/)(Component); +``` + +**2. Your customized `mapDispatchToProps` function return specifically contains `dispatch`** + +You may bring back `dispatch` by providing your customized `mapDispatchToProps` function: + +```js +const mapDispatchToProps = dispatch => { + return { + increment: () => dispatch(increment()), + decrement: () => dispatch(decrement()), + reset: () => dispatch(reset()), + dispatch + }; +}; +``` + +Or alternatively, with `bindActionCreators`: + +```js +import { bindActionCreators } from "redux"; + +function mapDispatchToProps(dispatch) { + return { + dispatch, + ...bindActionCreators({ increment, decrement, reset }, dispatch) + }; +} +``` + +See [this error in action in Redux’s GitHub issue #255](https://github.com/reduxjs/react-redux/issues/255). + +There are discussions regarding whether to provide `dispatch` to your components when you specify `mapDispatchToProps` ( [Dan Abramov’s response to #255](https://github.com/reduxjs/react-redux/issues/255#issuecomment-172089874) ). You may read them for further understanding of the current implementation intention. + +### Can I `mapDispatchToProps` without `mapStateToProps` in Redux? + +Yes. You can skip the first parameter by passing `undefined` or `null`. Your component will not subscribe to the store, and will still receive the dispatch props defined by `mapStateToProps`. + +```js +connect( + null, + mapDispatchToProps +)(MyComponent); +``` + +### Can I call `store.dispatch`? + +It's an anti-pattern to interact with the store directly in a React component, whether it's an explicit import of the store or accessing it via context (see the [Redux FAQ entry on store setup](https://redux.js.org/faq/storesetup#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) for more details). Let React-Redux’s `connect` handle the access to the store, and use the `dispatch` it passes to the props to dispatch actions. + +## Links and References + +**Tutorials** + +- [You Might Not Need the `mapDispatchToProps` Function](https://daveceddia.com/redux-mapdispatchtoprops-object-form/) + +**Related Docs** + +- [Redux Doc on `bindActionCreators`](https://redux.js.org/api/bindactioncreators) + +**Q&A** + +- [How to get simple dispatch from `this.props` using connect with Redux?](https://stackoverflow.com/questions/34458261/how-to-get-simple-dispatch-from-this-props-using-connect-w-redux) +- [`this.props.dispatch` is `undefined` if using `mapDispatchToProps`](https://github.com/reduxjs/react-redux/issues/255) +- [Do not call `store.dispatch`, call `this.props.dispatch` injected by `connect` instead](https://github.com/reduxjs/redux/issues/916) +- [Can I `mapDispatchToProps` without `mapStateToProps` in Redux?](https://stackoverflow.com/questions/47657365/can-i-mapdispatchtoprops-without-mapstatetoprops-in-redux) +- [Redux Doc FAQ: React Redux](https://redux.js.org/faq/reactredux) diff --git a/website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md b/website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md new file mode 100644 index 000000000..08fae115a --- /dev/null +++ b/website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md @@ -0,0 +1,249 @@ +--- +id: version-5.1.1-connect-mapstate +title: Connect: Extracting Data with mapStateToProps +hide_title: true +sidebar_label: Connect: Extracting Data with mapStateToProps +original_id: connect-mapstate +--- + +# Connect: Extracting Data with `mapStateToProps` +As the first argument passed in to `connect`, `mapStateToProps` is used for selecting the part of the data from the store that the connected component needs. It’s frequently referred to as just `mapState` for short. + +- It is called every time the store state changes. +- It receives the entire store state, and should return an object of data this component needs. + + +## Defining `mapStateToProps` + +`mapStateToProps` should be defined as a function: + +```js +function mapStateToProps(state, ownProps?) +``` + +It should take a first argument called `state`, optionally a second argument called `ownProps`, and return a plain object containing the data that the connected component needs. + +This function should be passed as the first argument to `connect`, and will be called every time when the Redux store state changes. If you do not wish to subscribe to the store, pass `null` or `undefined` to `connect` in place of `mapStateToProps`. + +**It does not matter if a `mapStateToProps` function is written using the `function` keyword (`function mapState(state) { }` ) or as an arrow function (`const mapState = (state) => { }` )** - it will work the same either way. + +### Arguments + +1. **`state`** +2. **`ownProps` (optional)** + +#### `state` + +The first argument to a `mapStateToProps` function is the entire Redux store state (the same value returned by a call to `store.getState()`). Because of this, the first argument is traditionally just called `state`. (While you can give the argument any name you want, calling it `store` would be incorrect - it's the "state value", not the "store instance".) + +The `mapStateToProps` function should always be written with at least `state` passed in. + +```js +// TodoList.js + +function mapStateToProps(state) { + const { todos } = state; + return { todoList: todos.allIds }; +}; + +export default connect(mapStateToProps)(TodoList); +``` + +#### `ownProps` (optional) + +You may define the function with a second argument, `ownProps`, if your component needs the data from its own props to retrieve data from the store. This argument will contain all of the props given to the wrapper component that was generated by `connect`. + +```js +// Todo.js + +function mapStateToProps(state, ownProps) { + const { visibilityFilter } = state; + const { id } = ownProps; + const todo = getTodoById(state, id); + + // component receives additionally: + return { todo, visibilityFilter }; +}; + +// Later, in your application, a parent component renders: + +// and your component receives props.id, props.todo, and props.visibilityFilter +``` + +You do not need to include values from `ownProps` in the object returned from `mapStateToProps`. `connect` will automatically merge those different prop sources into a final set of props. + +### Return + +Your `mapStateToProps` function should return a plain object that contains the data the component needs: + +- Each field in the object will become a prop for your actual component +- The values in the fields will be used to determine if your component needs to re-render + +For example: + +```js +function mapStateToProps(state) { + return { + a : 42, + todos : state.todos, + filter : state.visibilityFilter + } +} + +// component will receive: props.a, props.todos, and props.filter +``` + + +> Note: In advanced scenarios where you need more control over the rendering performance, `mapStateToProps` can also return a function. In this case, that function will be used as the final `mapStateToProps` for a particular component instance. This allows you to do per-instance memoization. See the [Advanced Usage]() section of the docs for more details, as well as [PR #279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds. Most apps never need this. + + +## Usage Guidelines + + +### Let `mapStateToProps` Reshape the Data from the Store + +`mapStateToProps` functions can, and should, do a lot more than just `return state.someSlice`. **They have the responsibility of "re-shaping" store data as needed for that component.** This may include returning a value as a specific prop name, combining pieces of data from different parts of the state tree, and transforming the store data in different ways. + + +### Use Selector Functions to Extract and Transform Data + +We highly encourage the use of "selector" functions to help encapsulate the process of extracting values from specific locations in the state tree. Memoized selector functions also play a key role in improving application performance (see the following sections in this page and the [Advanced Usage: Performance]() page for more details on why and how to use selectors.) + + +### `mapStateToProps` Functions Should Be Fast + +Whenever the store changes, all of the `mapStateToProps` functions of all of the connected components will run. Because of this, your `mapStateToProps` functions should run as fast as possible. This also means that a slow `mapStateToProps` function can be a potential bottleneck for your application. + +As part of the "re-shaping data" idea, `mapStateToProps` functions frequently need to transform data in various ways (such as filtering an array, mapping an array of IDs to their corresponding objects, or extracting plain JS values from Immutable.js objects). These transformations can often be expensive, both in terms of cost to execute the transformation, and whether the component re-renders as a result. If performance is a concern, ensure that these transformations are only run if the input values have changed. + + +### `mapStateToProps` Functions Should Be Pure and Synchronous + +Much like a Redux reducer, a `mapStateToProps` function should always be 100% pure and synchronous. It should simply take `state` (and `ownProps`) as arguments, and return the data the component needs as props. It should _not_ be used to trigger asynchronous behavior like AJAX calls for data fetching, and the functions should not be declared as `async`. + + + +## `mapStateToProps` and Performance + + +### Return Values Determine If Your Component Re-Renders + +React-Redux internally implements the `shouldComponentUpdate` method such that the wrapper component re-renders precisely when the data your component needs has changed. By default, React-Redux decides whether the contents of the object returned from `mapStateToProps` are different using `===` comparison (a "shallow equality" check) on each fields of the returned object. If any of the fields have changed, then your component will be re-rendered so it can receive the updated values as props. Note that returning a mutated object of the same reference is a common mistake that can result in your component not re-rendering when expected. + + +To summarize the behavior of the component wrapped by `connect` with `mapStateToProps` to extract data from the store: + +| | `(state) => stateProps` | `(state, ownProps) => stateProps` | +| ---------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------- | +| `mapStateToProps` runs when: | store `state` changes | store `state` changes
or
any field of `ownProps` is different | +| component re-renders when: | any field of `stateProps` is different | any field of `stateProps` is different
or
any field of `ownProps` is different | + + +### Only Return New Object References If Needed + +React-Redux does shallow comparisons to see if the `mapStateToProps` results have changed. It’s easy to accidentally return new object or array references every time, which would cause your component to re-render even if the data is actually the same. + +Many common operations result in new object or array references being created: + +- Creating new arrays with `someArray.map()` or `someArray.filter()` +- Merging arrays with `array.concat` +- Selecting portion of an array with `array.slice` +- Copying values with `Object.assign` +- Copying values with the spread operator `{ ...oldState, ...newData }` + +Put these operations in [memoized selector functions]() to ensure that they only run if the input values have changed. This will also ensure that if the input values _haven't_ changed, `mapStateToProps` will still return the same result values as before, and `connect` can skip re-rendering. + + + +### Only Perform Expensive Operations When Data Changes + +Transforming data can often be expensive (_and_ usually results in new object references being created). In order for your `mapStateToProps` function to be as fast as possible, you should only re-run these complex transformations when the relevant data has changed. + +There are a few ways to approach this: + +- Some transformations could be calculated in an action creator or reducer, and the transformed data could be kept in the store +- Transformations can also be done in a component's `render()` method +- If the transformation does need to be done in a `mapStateToProps` function, then we recommend using [memoized selector functions]() to ensure the transformation is only run when the input values have changed. + + +#### Immutable.js Performance Concerns + +Immutable.js author Lee Byron on Twitter [explicitly advises avoiding `toJS` when performance is a concern](https://twitter.com/leeb/status/746733697093668864?lang=en): + +> Perf tip for #immutablejs: avoid .toJS() .toObject() and .toArray() all slow full-copy operations which render structural sharing useless. + +There's several other performance concerns to take into consideration with Immutable.js - see the list of links at the end of this page for more information. + + + +## Behavior and Gotchas + + +### `mapStateToProps` Will Not Run if the Store State is the Same + +The wrapper component generated by `connect` subscribes to the Redux store. Every time an action is dispatched, it calls `store.getState()` and checks to see if `lastState === currentState`. If the two state values are identical by reference, then it will _not_ re-run your `mapStateToProps` function, because it assumes that the rest of the store state hasn't changed either. + +The Redux `combineReducers` utility function tries to optimize for this. If none of the slice reducers returned a new value, then `combineReducers` returns the old state object instead of a new one. This means that mutation in a reducer can lead to the root state object not being updated, and thus the UI won't re-render. + + + +### The Number of Declared Arguments Affects Behavior + +With just `(state)`, the function runs whenever the root store state object is different. With `(state, ownProps)`, it runs any time the store state is different and ALSO whenever the wrapper props have changed. + +This means that **you should not add the `ownProps` argument unless you actually need to use it**, or your `mapStateToProps` function will run more often than it needs to. + + +There are some edge cases around this behavior. **The number of mandatory arguments determines whether `mapStateToProps` will receive `ownProps`**. + +If the formal definition of the function contains one mandatory parameter, `mapStateToProps` will _not_ receive `ownProps`: + +```js +function mapStateToProps(state) { + console.log(state); // state + console.log(arguments[1]); // undefined +} +const mapStateToProps = (state, ownProps = {}) => { + console.log(state); // state + console.log(ownProps); // undefined +} +``` + +It _will_ receive `ownProps` when the formal definition of the function contains zero or two mandatory parameters: + +```js +function mapStateToProps(state, ownProps) { + console.log(state); // state + console.log(ownProps); // ownProps +} + +function mapStateToProps() { + console.log(arguments[0]); // state + console.log(arguments[1]); // ownProps +} + +function mapStateToProps(...args) { + console.log(args[0]); // state + console.log(args[1]); // ownProps +} +``` + +## Links and References + +**Tutorials** + +- [Practical Redux Series, Part 6: Connected Lists, Forms, and Performance](https://blog.isquaredsoftware.com/2017/01/practical-redux-part-6-connected-lists-forms-and-performance/) +- [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) + +**Performance** + +- [Lee Byron's Tweet Suggesting to avoid `toJS`, `toArray` and `toObject` for Performance](https://twitter.com/leeb/status/746733697093668864) +- [Improving React and Redux performance with Reselect](https://blog.rangle.io/react-and-redux-performance-with-reselect/) +- [Immutable data performance links](https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data) + +**Q&A** + +- [Why Is My Component Re-Rendering Too Often?](https://redux.js.org/faq/reactredux#why-is-my-component-re-rendering-too-often) +- [Why isn't my component re-rendering, or my mapStateToProps running](https://redux.js.org/faq/reactredux#why-isnt-my-component-re-rendering-or-my-mapstatetoprops-running) +- [How can I speed up my mapStateToProps?](https://redux.js.org/faq/reactredux#why-is-my-component-re-rendering-too-often) +- [Should I only connect my top component, or can I connect multiple components in my tree?](https://redux.js.org/faq/reactredux#why-is-my-component-re-rendering-too-often) diff --git a/website/versioned_sidebars/version-5.1.1-sidebars.json b/website/versioned_sidebars/version-5.1.1-sidebars.json new file mode 100644 index 000000000..d2b32e3b2 --- /dev/null +++ b/website/versioned_sidebars/version-5.1.1-sidebars.json @@ -0,0 +1,20 @@ +{ + "version-5.1.1-docs": { + "Introduction": [ + "version-5.1.1-introduction/quick-start", + "version-5.1.1-introduction/basic-tutorial", + "version-5.1.1-introduction/why-use-react-redux" + ], + "Using React-Redux": [ + "version-5.1.1-using-react-redux/connect-mapstate", + "version-5.1.1-using-react-redux/connect-mapdispatch" + ], + "API Reference": [ + "version-5.1.1-api", + "version-5.1.1-api/provider" + ], + "Guides": [ + "version-5.1.1-troubleshooting" + ] + } +} diff --git a/website/versions.json b/website/versions.json new file mode 100644 index 000000000..be0c5e4f8 --- /dev/null +++ b/website/versions.json @@ -0,0 +1,3 @@ +[ + "5.1.1" +] From 5a30cfccc87c71ae4ceaed6b5be6dad88eff0a6d Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Sat, 8 Dec 2018 12:13:32 +0800 Subject: [PATCH 2/5] Start adding 6.0 docs --- docs/api.md | 51 +-- website/pages/en/versions.js | 3 +- website/versioned_docs/version-6.0.0/api.md | 448 ++++++++++++++++++++ website/versions.json | 1 + 4 files changed, 454 insertions(+), 49 deletions(-) create mode 100644 website/versioned_docs/version-6.0.0/api.md diff --git a/docs/api.md b/docs/api.md index 155d7b444..2ce3bef51 100644 --- a/docs/api.md +++ b/docs/api.md @@ -87,7 +87,6 @@ It does not modify the component class passed to it; instead, it *returns* a new * [`areOwnPropsEqual`] *(Function)*: When pure, compares incoming props to its previous value. Default value: `shallowEqual` * [`areStatePropsEqual`] *(Function)*: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` * [`areMergedPropsEqual`] *(Function)*: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` - * [`storeKey`] *(String)*: The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` #### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps @@ -392,9 +391,7 @@ It does not modify the component class passed to it; instead, it *returns* a new * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` - * [`storeKey`] *(String)*: the key of props/context to get the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` - - * [`withRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` + * [`forwardRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. @@ -416,7 +413,7 @@ All the original static methods of the component are hoisted. ##### `getWrappedInstance(): ReactComponent` -Returns the wrapped component instance. Only available if you pass `{ withRef: true }` as part of the `options` argument. +Returns the wrapped component instance. Only available if you pass `{ forwardRef: true }` as part of the `options` argument. ### Remarks @@ -446,46 +443,4 @@ function selectorFactory(dispatch) { return result } } -export default connectAdvanced(selectorFactory)(TodoApp) -``` - -## createProvider - -```js -createProvider([storeKey]) -``` - -Creates a new `` which will set the Redux Store on the passed key of the context. You probably only need this if you are in the inadvisable position of having multiple stores. You will also need to pass the same `storeKey` to the `options` argument of [`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) - -### Arguments - -* [`storeKey`] (*String*): The key of the context on which to set the store. Default value: `'store'` - -### Examples -Before creating multiple stores, please go through this FAQ: [Can or should I create multiple stores?](http://redux.js.org/docs/faq/StoreSetup.html#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) - -```js -import {connect, createProvider} from 'react-redux' - -const STORE_KEY = 'componentStore' - -export const Provider = createProvider(STORE_KEY) - -function connectExtended( - mapStateToProps, - mapDispatchToProps, - mergeProps, - options = {} -) { - options.storeKey = STORE_KEY - return connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, - options - ) -} - -export {connectExtended as connect} -``` -Now you can import the above `Provider` and `connect` and use them. +export default connectAdvanced(selectorFactory)(TodoApp) \ No newline at end of file diff --git a/website/pages/en/versions.js b/website/pages/en/versions.js index fa44ed876..b90ef4e97 100644 --- a/website/pages/en/versions.js +++ b/website/pages/en/versions.js @@ -48,6 +48,7 @@ This is the version that is configured automatically when you first install this project.

+ {/* uncomment here if we have pre-release notes

Pre-release versions

@@ -61,7 +62,7 @@ -
+ */}

Past Versions

diff --git a/website/versioned_docs/version-6.0.0/api.md b/website/versioned_docs/version-6.0.0/api.md new file mode 100644 index 000000000..46455ebd4 --- /dev/null +++ b/website/versioned_docs/version-6.0.0/api.md @@ -0,0 +1,448 @@ +--- +id: version-6.0.0-api +title: Api +sidebar_label: API +hide_title: true +original_id: api +--- + +# API + + +## Provider + +Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. + +If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +### Props + +* `store` (*[Redux Store](https://redux.js.org/api-reference/store)*): The single Redux store in your application. +* `children` (*ReactElement*) The root of your component hierarchy. + +### Example + +#### Vanilla React + +```jsx +ReactDOM.render( + + + , + rootEl +) +``` + +#### React Router + +```jsx +ReactDOM.render( + + + + + + + + , + document.getElementById('root') +) +``` + + +## connect + +``` +connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) +``` + +Connects a React component to a Redux store. `connect` is a facade around `connectAdvanced`, providing a convenient API for the most common use cases. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* [`mapStateToProps(state, [ownProps]): stateProps`] \(*Function*): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into the component’s props. If you don't want to subscribe to store updates, pass `null` or `undefined` in place of `mapStateToProps`. + + If your `mapStateToProps` function is declared as taking two parameters, it will be called with the store state as the first parameter and the props passed to the connected component as the second parameter, and will also be re-invoked whenever the connected component receives new props as determined by shallow equality comparisons. (The second parameter is normally referred to as `ownProps` by convention.) + + >Note: in advanced scenarios where you need more control over the rendering performance, `mapStateToProps()` can also return a function. In this case, *that* function will be used as `mapStateToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + + >The `mapStateToProps` function's first argument is the entire Redux store’s state and it returns an object to be passed as props. It is often called a **selector**. Use [reselect](https://github.com/reduxjs/reselect) to efficiently compose selectors and [compute derived data](https://redux.js.org/recipes/computing-derived-data). + +* [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(*Object* or *Function*): If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a `dispatch` call so they may be invoked directly, will be merged into the component’s props. + + If a function is passed, it will be given `dispatch` as the first parameter. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](https://redux.js.org/api-reference/bindactioncreators) helper from Redux.) + + If your `mapDispatchToProps` function is declared as taking two parameters, it will be called with `dispatch` as the first parameter and the props passed to the connected component as the second parameter, and will be re-invoked whenever the connected component receives new props. (The second parameter is normally referred to as `ownProps` by convention.) + + If you do not supply your own `mapDispatchToProps` function or object full of action creators, the default `mapDispatchToProps` implementation just injects `dispatch` into your component’s props. + + >Note: in advanced scenarios where you need more control over the rendering performance, `mapDispatchToProps()` can also return a function. In this case, *that* function will be used as `mapDispatchToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + +* [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(*Function*): If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, dispatchProps)` is used by default. + +* [`options`] *(Object)* If specified, further customizes the behavior of the connector. In addition to the options passable to `connectAdvanced()` (see those below), `connect()` accepts these additional options: + * [`pure`] *(Boolean)*: If true, `connect()` will avoid re-renders and calls to `mapStateToProps`, `mapDispatchToProps`, and `mergeProps` if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: `true` + * [`areStatesEqual`] *(Function)*: When pure, compares incoming store state to its previous value. Default value: `strictEqual (===)` + * [`areOwnPropsEqual`] *(Function)*: When pure, compares incoming props to its previous value. Default value: `shallowEqual` + * [`areStatePropsEqual`] *(Function)*: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` + * [`areMergedPropsEqual`] *(Function)*: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` + +#### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps + +> Note: `ownProps` **is not passed** to `mapStateToProps` and `mapDispatchToProps` if the formal definition of the function contains one mandatory parameter (function has length 1). For example, functions defined like below won't receive `ownProps` as the second argument. + +```js +function mapStateToProps(state) { + console.log(state); // state + console.log(arguments[1]); // undefined +} +``` +```js +const mapStateToProps = (state, ownProps = {}) => { + console.log(state); // state + console.log(ownProps); // {} +} +``` + +Functions with no mandatory parameters or two parameters **will receive** `ownProps`. +```js +const mapStateToProps = (state, ownProps) => { + console.log(state); // state + console.log(ownProps); // ownProps +} +``` +```js +function mapStateToProps() { + console.log(arguments[0]); // state + console.log(arguments[1]); // ownProps +} +``` +```js +const mapStateToProps = (...args) => { + console.log(args[0]); // state + console.log(args[1]); // ownProps +} +``` + +#### Optimizing connect when options.pure is true + +When `options.pure` is true, `connect` performs several equality checks that are used to avoid unnecessary calls to `mapStateToProps`, `mapDispatchToProps`, `mergeProps`, and ultimately to `render`. These include `areStatesEqual`, `areOwnPropsEqual`, `areStatePropsEqual`, and `areMergedPropsEqual`. While the defaults are probably appropriate 99% of the time, you may wish to override them with custom implementations for performance or other reasons. Here are several examples: + +* You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. For example: `areStatesEqual: (next, prev) => prev.entities.todos === next.entities.todos`; this would effectively ignore state changes for everything but that slice of state. + +* You may wish to override `areStatesEqual` to always return false (`areStatesEqual: () => false`) if you have impure reducers that mutate your store state. (This would likely impact the other equality checks as well, depending on your `mapStateToProps` function.) + +* You may wish to override `areOwnPropsEqual` as a way to whitelist incoming props. You'd also have to implement `mapStateToProps`, `mapDispatchToProps` and `mergeProps` to also whitelist props. (It may be simpler to achieve this other ways, for example by using [recompose's mapProps](https://github.com/acdlite/recompose/blob/master/docs/API.md#mapprops).) + +* You may wish to override `areStatePropsEqual` to use `strictEqual` if your `mapStateToProps` uses a memoized selector that will only return a new object if a relevant prop has changed. This would be a very slight performance improvement, since would avoid extra equality checks on individual props each time `mapStateToProps` is called. + +* You may wish to override `areMergedPropsEqual` to implement a `deepEqual` if your selectors produce complex props. ex: nested objects, new arrays, etc. (The deep equal check should be faster than just re-rendering.) + +### Returns + +A higher-order React component class that passes state and action creators into your component derived from the supplied arguments. This is created by `connectAdvanced`, and details of this higher-order component are covered there. + + +#### Examples + +#### Inject just `dispatch` and don't listen to store + +```js +export default connect()(TodoApp) +``` + +#### Inject all action creators (`addTodo`, `completeTodo`, ...) without subscribing to the store + +```js +import * as actionCreators from './actionCreators' + +export default connect(null, actionCreators)(TodoApp) +``` + +#### Inject `dispatch` and every field in the global state + +>Don’t do this! It kills any performance optimizations because `TodoApp` will rerender after every state change. +>It’s better to have more granular `connect()` on several components in your view hierarchy that each only +>listen to a relevant slice of the state. + +```js +export default connect(state => state)(TodoApp) +``` + +#### Inject `dispatch` and `todos` + +```js +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps)(TodoApp) +``` + +#### Inject `todos` and all action creators + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps, actionCreators)(TodoApp) +``` + +#### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) as `actions` + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { actions: bindActionCreators(actionCreators, dispatch) } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` and a specific action creator (`addTodo`) + +```js +import { addTodo } from './actionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators({ addTodo }, dispatch) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` and specific action creators (`addTodo` and `deleteTodo`) with shorthand syntax + +```js +import { addTodo, deleteTodo } from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +const mapDispatchToProps = { + addTodo, + deleteTodo +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, todoActionCreators as `todoActions`, and counterActionCreators as `counterActions` + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { + todoActions: bindActionCreators(todoActionCreators, dispatch), + counterActions: bindActionCreators(counterActionCreators, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, and todoActionCreators and counterActionCreators together as `actions` + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos`, and all todoActionCreators and counterActionCreators directly as props + +```js +import * as todoActionCreators from './todoActionCreators' +import * as counterActionCreators from './counterActionCreators' +import { bindActionCreators } from 'redux' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) +``` + +#### Inject `todos` of a specific user depending on props + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state, ownProps) { + return { todos: state.todos[ownProps.userId] } +} + +export default connect(mapStateToProps)(TodoApp) +``` + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' + +function mapStateToProps(state) { + return { todos: state.todos } +} + +function mergeProps(stateProps, dispatchProps, ownProps) { + return Object.assign({}, ownProps, { + todos: stateProps.todos[ownProps.userId], + addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text) + }) +} + +export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp) +``` + +#### Factory functions + +Factory functions can be used for performance optimizations + +```js +import { addTodo } from './actionCreators' + +function mapStateToPropsFactory(initialState, initialProps) { + const getSomeProperty= createSelector(...); + const anotherProperty = 200 + initialState[initialProps.another]; + return function(state){ + return { + anotherProperty, + someProperty: getSomeProperty(state), + todos: state.todos + } + } +} + +function mapDispatchToPropsFactory(initialState, initialProps) { + function goToSomeLink(){ + initialProps.history.push('some/link'); + } + return function(dispatch){ + return { + addTodo + } + } +} + + +export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp) +``` + +## connectAdvanced + +```js +connectAdvanced(selectorFactory, [connectOptions]) +``` + +Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(*Function*): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. + +* [`connectOptions`] *(Object)* If specified, further customizes the behavior of the connector. + + * [`getDisplayName`] *(Function)*: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` + + * [`methodName`] *(String)*: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` + + * [`renderCountProp`] *(String)*: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` + + * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` + + * [`forwardRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` + + * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. + + + +### Returns + +A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. + +#### Static Properties + +* `WrappedComponent` *(Component)*: The original component class passed to `connectAdvanced(...)(Component)`. + +#### Static Methods + +All the original static methods of the component are hoisted. + +#### Instance Methods + +##### `getWrappedInstance(): ReactComponent` + +Returns the wrapped component instance. Only available if you pass `{ forwardRef: true }` as part of the `options` argument. + +### Remarks + +* Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. + +* `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. + + +#### Examples + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function selectorFactory(dispatch) { + let ownProps = {} + let result = {} + const actions = bindActionCreators(actionCreators, dispatch) + const addTodo = (text) => actions.addTodo(ownProps.userId, text) + return (nextState, nextOwnProps) => { + const todos = nextState.todos[nextOwnProps.userId] + const nextResult = { ...nextOwnProps, todos, addTodo } + ownProps = nextOwnProps + if (!shallowEqual(result, nextResult)) result = nextResult + return result + } +} +export default connectAdvanced(selectorFactory)(TodoApp) +``` \ No newline at end of file diff --git a/website/versions.json b/website/versions.json index be0c5e4f8..e2c5a88ab 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,3 +1,4 @@ [ + "6.0.0", "5.1.1" ] From a72657972169d2d59a90c0c90b31fa48d924651e Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Sun, 7 Apr 2019 12:42:53 +0800 Subject: [PATCH 3/5] Rename 5.1.1 to 5.x and make it work --- website/siteConfig.js | 2 +- .../versioned_docs/version-5.1.1/api/api.md | 492 ------------------ .../{version-5.1.1 => version-5.x}/api.md | 2 +- .../api/Provider.md | 43 +- website/versioned_docs/version-5.x/api/api.md | 51 ++ .../version-5.x/api/connect-advanced.md | 88 ++++ .../api.md => version-5.x/api/connect.md} | 133 +---- .../introduction/basic-tutorial.md | 2 +- .../introduction/quick-start.md | 2 +- .../introduction/why-use-react-redux.md | 2 +- .../troubleshooting.md | 2 +- ...atching-actions-with-mapDispatchToProps.md | 2 +- ...ct-extracting-data-with-mapStateToProps.md | 2 +- .../version-5.1.1-sidebars.json | 20 - .../version-5.x-sidebars.json | 22 + website/versions.json | 3 +- 16 files changed, 217 insertions(+), 651 deletions(-) delete mode 100644 website/versioned_docs/version-5.1.1/api/api.md rename website/versioned_docs/{version-5.1.1 => version-5.x}/api.md (99%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/api/Provider.md (62%) create mode 100644 website/versioned_docs/version-5.x/api/api.md create mode 100644 website/versioned_docs/version-5.x/api/connect-advanced.md rename website/versioned_docs/{version-6.0.0/api.md => version-5.x/api/connect.md} (72%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/introduction/basic-tutorial.md (99%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/introduction/quick-start.md (97%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/introduction/why-use-react-redux.md (99%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/troubleshooting.md (99%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md (99%) rename website/versioned_docs/{version-5.1.1 => version-5.x}/using-react-redux/connect-extracting-data-with-mapStateToProps.md (99%) delete mode 100644 website/versioned_sidebars/version-5.1.1-sidebars.json create mode 100644 website/versioned_sidebars/version-5.x-sidebars.json diff --git a/website/siteConfig.js b/website/siteConfig.js index fd9f2788f..4b2ff280e 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -98,7 +98,7 @@ const siteConfig = { // template. For example, if you need your repo's URL... repoUrl: "https://github.com/reduxjs/react-redux", - nextVersion: "6.0.0", + // nextVersion: "6.0.0", gaTrackingId : "UA-130598673-2", }; diff --git a/website/versioned_docs/version-5.1.1/api/api.md b/website/versioned_docs/version-5.1.1/api/api.md deleted file mode 100644 index 4440b6950..000000000 --- a/website/versioned_docs/version-5.1.1/api/api.md +++ /dev/null @@ -1,492 +0,0 @@ ---- -id: version-5.1.1-api -title: Api -sidebar_label: API -hide_title: true -original_id: api ---- - -# API - - -## Provider - -Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. - -If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. - -### Props - -* `store` (*[Redux Store](https://redux.js.org/api-reference/store)*): The single Redux store in your application. -* `children` (*ReactElement*) The root of your component hierarchy. - -### Example - -#### Vanilla React - -```jsx -ReactDOM.render( - - - , - rootEl -) -``` - -#### React Router - -```jsx -ReactDOM.render( - - - - - - - - , - document.getElementById('root') -) -``` - - -## connect - -``` -connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) -``` - -Connects a React component to a Redux store. `connect` is a facade around `connectAdvanced`, providing a convenient API for the most common use cases. - -It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. - -### Arguments - -* [`mapStateToProps(state, [ownProps]): stateProps`] \(*Function*): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into the component’s props. If you don't want to subscribe to store updates, pass `null` or `undefined` in place of `mapStateToProps`. - - If your `mapStateToProps` function is declared as taking two parameters, it will be called with the store state as the first parameter and the props passed to the connected component as the second parameter, and will also be re-invoked whenever the connected component receives new props as determined by shallow equality comparisons. (The second parameter is normally referred to as `ownProps` by convention.) - - >Note: in advanced scenarios where you need more control over the rendering performance, `mapStateToProps()` can also return a function. In this case, *that* function will be used as `mapStateToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. - - >The `mapStateToProps` function's first argument is the entire Redux store’s state and it returns an object to be passed as props. It is often called a **selector**. Use [reselect](https://github.com/reduxjs/reselect) to efficiently compose selectors and [compute derived data](https://redux.js.org/recipes/computing-derived-data). - -* [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(*Object* or *Function*): If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a `dispatch` call so they may be invoked directly, will be merged into the component’s props. - - If a function is passed, it will be given `dispatch` as the first parameter. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](https://redux.js.org/api-reference/bindactioncreators) helper from Redux.) - - If your `mapDispatchToProps` function is declared as taking two parameters, it will be called with `dispatch` as the first parameter and the props passed to the connected component as the second parameter, and will be re-invoked whenever the connected component receives new props. (The second parameter is normally referred to as `ownProps` by convention.) - - If you do not supply your own `mapDispatchToProps` function or object full of action creators, the default `mapDispatchToProps` implementation just injects `dispatch` into your component’s props. - - >Note: in advanced scenarios where you need more control over the rendering performance, `mapDispatchToProps()` can also return a function. In this case, *that* function will be used as `mapDispatchToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. - -* [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(*Function*): If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, dispatchProps)` is used by default. - -* [`options`] *(Object)* If specified, further customizes the behavior of the connector. In addition to the options passable to `connectAdvanced()` (see those below), `connect()` accepts these additional options: - * [`pure`] *(Boolean)*: If true, `connect()` will avoid re-renders and calls to `mapStateToProps`, `mapDispatchToProps`, and `mergeProps` if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: `true` - * [`areStatesEqual`] *(Function)*: When pure, compares incoming store state to its previous value. Default value: `strictEqual (===)` - * [`areOwnPropsEqual`] *(Function)*: When pure, compares incoming props to its previous value. Default value: `shallowEqual` - * [`areStatePropsEqual`] *(Function)*: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` - * [`areMergedPropsEqual`] *(Function)*: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` - * [`storeKey`] *(String)*: The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` - -#### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps - -> Note: `ownProps` **is not passed** to `mapStateToProps` and `mapDispatchToProps` if the formal definition of the function contains one mandatory parameter (function has length 1). For example, functions defined like below won't receive `ownProps` as the second argument. - -```js -function mapStateToProps(state) { - console.log(state); // state - console.log(arguments[1]); // undefined -} -``` -```js -const mapStateToProps = (state, ownProps = {}) => { - console.log(state); // state - console.log(ownProps); // {} -} -``` - -Functions with no mandatory parameters or two parameters **will receive** `ownProps`. -```js -const mapStateToProps = (state, ownProps) => { - console.log(state); // state - console.log(ownProps); // ownProps -} -``` -```js -function mapStateToProps() { - console.log(arguments[0]); // state - console.log(arguments[1]); // ownProps -} -``` -```js -const mapStateToProps = (...args) => { - console.log(args[0]); // state - console.log(args[1]); // ownProps -} -``` - -#### Optimizing connect when options.pure is true - -When `options.pure` is true, `connect` performs several equality checks that are used to avoid unnecessary calls to `mapStateToProps`, `mapDispatchToProps`, `mergeProps`, and ultimately to `render`. These include `areStatesEqual`, `areOwnPropsEqual`, `areStatePropsEqual`, and `areMergedPropsEqual`. While the defaults are probably appropriate 99% of the time, you may wish to override them with custom implementations for performance or other reasons. Here are several examples: - -* You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. For example: `areStatesEqual: (next, prev) => prev.entities.todos === next.entities.todos`; this would effectively ignore state changes for everything but that slice of state. - -* You may wish to override `areStatesEqual` to always return false (`areStatesEqual: () => false`) if you have impure reducers that mutate your store state. (This would likely impact the other equality checks as well, depending on your `mapStateToProps` function.) - -* You may wish to override `areOwnPropsEqual` as a way to whitelist incoming props. You'd also have to implement `mapStateToProps`, `mapDispatchToProps` and `mergeProps` to also whitelist props. (It may be simpler to achieve this other ways, for example by using [recompose's mapProps](https://github.com/acdlite/recompose/blob/master/docs/API.md#mapprops).) - -* You may wish to override `areStatePropsEqual` to use `strictEqual` if your `mapStateToProps` uses a memoized selector that will only return a new object if a relevant prop has changed. This would be a very slight performance improvement, since would avoid extra equality checks on individual props each time `mapStateToProps` is called. - -* You may wish to override `areMergedPropsEqual` to implement a `deepEqual` if your selectors produce complex props. ex: nested objects, new arrays, etc. (The deep equal check should be faster than just re-rendering.) - -### Returns - -A higher-order React component class that passes state and action creators into your component derived from the supplied arguments. This is created by `connectAdvanced`, and details of this higher-order component are covered there. - - -#### Examples - -#### Inject just `dispatch` and don't listen to store - -```js -export default connect()(TodoApp) -``` - -#### Inject all action creators (`addTodo`, `completeTodo`, ...) without subscribing to the store - -```js -import * as actionCreators from './actionCreators' - -export default connect(null, actionCreators)(TodoApp) -``` - -#### Inject `dispatch` and every field in the global state - ->Don’t do this! It kills any performance optimizations because `TodoApp` will rerender after every state change. ->It’s better to have more granular `connect()` on several components in your view hierarchy that each only ->listen to a relevant slice of the state. - -```js -export default connect(state => state)(TodoApp) -``` - -#### Inject `dispatch` and `todos` - -```js -function mapStateToProps(state) { - return { todos: state.todos } -} - -export default connect(mapStateToProps)(TodoApp) -``` - -#### Inject `todos` and all action creators - -```js -import * as actionCreators from './actionCreators' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -export default connect(mapStateToProps, actionCreators)(TodoApp) -``` - -#### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) as `actions` - -```js -import * as actionCreators from './actionCreators' -import { bindActionCreators } from 'redux' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -function mapDispatchToProps(dispatch) { - return { actions: bindActionCreators(actionCreators, dispatch) } -} - -export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) -``` - -#### Inject `todos` and a specific action creator (`addTodo`) - -```js -import { addTodo } from './actionCreators' -import { bindActionCreators } from 'redux' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators({ addTodo }, dispatch) -} - -export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) -``` - -#### Inject `todos` and specific action creators (`addTodo` and `deleteTodo`) with shorthand syntax - -```js -import { addTodo, deleteTodo } from './actionCreators' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -const mapDispatchToProps = { - addTodo, - deleteTodo -} - -export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) -``` - -#### Inject `todos`, todoActionCreators as `todoActions`, and counterActionCreators as `counterActions` - -```js -import * as todoActionCreators from './todoActionCreators' -import * as counterActionCreators from './counterActionCreators' -import { bindActionCreators } from 'redux' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -function mapDispatchToProps(dispatch) { - return { - todoActions: bindActionCreators(todoActionCreators, dispatch), - counterActions: bindActionCreators(counterActionCreators, dispatch) - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) -``` - -#### Inject `todos`, and todoActionCreators and counterActionCreators together as `actions` - -```js -import * as todoActionCreators from './todoActionCreators' -import * as counterActionCreators from './counterActionCreators' -import { bindActionCreators } from 'redux' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -function mapDispatchToProps(dispatch) { - return { - actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) -``` - -#### Inject `todos`, and all todoActionCreators and counterActionCreators directly as props - -```js -import * as todoActionCreators from './todoActionCreators' -import * as counterActionCreators from './counterActionCreators' -import { bindActionCreators } from 'redux' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch) -} - -export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) -``` - -#### Inject `todos` of a specific user depending on props - -```js -import * as actionCreators from './actionCreators' - -function mapStateToProps(state, ownProps) { - return { todos: state.todos[ownProps.userId] } -} - -export default connect(mapStateToProps)(TodoApp) -``` - -#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action - -```js -import * as actionCreators from './actionCreators' - -function mapStateToProps(state) { - return { todos: state.todos } -} - -function mergeProps(stateProps, dispatchProps, ownProps) { - return Object.assign({}, ownProps, { - todos: stateProps.todos[ownProps.userId], - addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text) - }) -} - -export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp) -``` - -#### Factory functions - -Factory functions can be used for performance optimizations - -```js -import { addTodo } from './actionCreators' - -function mapStateToPropsFactory(initialState, initialProps) { - const getSomeProperty= createSelector(...); - const anotherProperty = 200 + initialState[initialProps.another]; - return function(state){ - return { - anotherProperty, - someProperty: getSomeProperty(state), - todos: state.todos - } - } -} - -function mapDispatchToPropsFactory(initialState, initialProps) { - function goToSomeLink(){ - initialProps.history.push('some/link'); - } - return function(dispatch){ - return { - addTodo - } - } -} - - -export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp) -``` - -## connectAdvanced - -```js -connectAdvanced(selectorFactory, [connectOptions]) -``` - -Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. - -It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. - -### Arguments - -* `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(*Function*): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. - -* [`connectOptions`] *(Object)* If specified, further customizes the behavior of the connector. - - * [`getDisplayName`] *(Function)*: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` - - * [`methodName`] *(String)*: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` - - * [`renderCountProp`] *(String)*: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` - - * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` - - * [`storeKey`] *(String)*: the key of props/context to get the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` - - * [`withRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` - - * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. - - - -### Returns - -A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. - -#### Static Properties - -* `WrappedComponent` *(Component)*: The original component class passed to `connectAdvanced(...)(Component)`. - -#### Static Methods - -All the original static methods of the component are hoisted. - -#### Instance Methods - -##### `getWrappedInstance(): ReactComponent` - -Returns the wrapped component instance. Only available if you pass `{ withRef: true }` as part of the `options` argument. - -### Remarks - -* Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. - -* `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. - - -#### Examples - -#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action - -```js -import * as actionCreators from './actionCreators' -import { bindActionCreators } from 'redux' - -function selectorFactory(dispatch) { - let ownProps = {} - let result = {} - const actions = bindActionCreators(actionCreators, dispatch) - const addTodo = (text) => actions.addTodo(ownProps.userId, text) - return (nextState, nextOwnProps) => { - const todos = nextState.todos[nextOwnProps.userId] - const nextResult = { ...nextOwnProps, todos, addTodo } - ownProps = nextOwnProps - if (!shallowEqual(result, nextResult)) result = nextResult - return result - } -} -export default connectAdvanced(selectorFactory)(TodoApp) -``` - -## createProvider - -```js -createProvider([storeKey]) -``` - -Creates a new `` which will set the Redux Store on the passed key of the context. You probably only need this if you are in the inadvisable position of having multiple stores. You will also need to pass the same `storeKey` to the `options` argument of [`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) - -### Arguments - -* [`storeKey`] (*String*): The key of the context on which to set the store. Default value: `'store'` - -### Examples -Before creating multiple stores, please go through this FAQ: [Can or should I create multiple stores?](http://redux.js.org/docs/faq/StoreSetup.html#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) - -```js -import {connect, createProvider} from 'react-redux' - -const STORE_KEY = 'componentStore' - -export const Provider = createProvider(STORE_KEY) - -function connectExtended( - mapStateToProps, - mapDispatchToProps, - mergeProps, - options = {} -) { - options.storeKey = STORE_KEY - return connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, - options - ) -} - -export {connectExtended as connect} -``` -Now you can import the above `Provider` and `connect` and use them. diff --git a/website/versioned_docs/version-5.1.1/api.md b/website/versioned_docs/version-5.x/api.md similarity index 99% rename from website/versioned_docs/version-5.1.1/api.md rename to website/versioned_docs/version-5.x/api.md index 4440b6950..9f5088d4d 100644 --- a/website/versioned_docs/version-5.1.1/api.md +++ b/website/versioned_docs/version-5.x/api.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-api +id: version-5.x-api title: Api sidebar_label: API hide_title: true diff --git a/website/versioned_docs/version-5.1.1/api/Provider.md b/website/versioned_docs/version-5.x/api/Provider.md similarity index 62% rename from website/versioned_docs/version-5.1.1/api/Provider.md rename to website/versioned_docs/version-5.x/api/Provider.md index 7a6ad50f5..2f0852feb 100644 --- a/website/versioned_docs/version-5.1.1/api/Provider.md +++ b/website/versioned_docs/version-5.x/api/Provider.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-provider +id: version-5.x-provider title: Provider sidebar_label: Provider original_id: provider @@ -78,3 +78,44 @@ In the example below, the `` component is our root-level component. This document.getElementById('root') ) ``` + +## createProvider + +```js +createProvider([storeKey]) +``` + +Creates a new `` which will set the Redux Store on the passed key of the context. You probably only need this if you are in the inadvisable position of having multiple stores. You will also need to pass the same `storeKey` to the `options` argument of [`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) + +### Arguments + +* [`storeKey`] (*String*): The key of the context on which to set the store. Default value: `'store'` + +### Examples +Before creating multiple stores, please go through this FAQ: [Can or should I create multiple stores?](http://redux.js.org/docs/faq/StoreSetup.html#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) + +```js +import {connect, createProvider} from 'react-redux' + +const STORE_KEY = 'componentStore' + +export const Provider = createProvider(STORE_KEY) + +function connectExtended( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options = {} +) { + options.storeKey = STORE_KEY + return connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options + ) +} + +export {connectExtended as connect} +``` +Now you can import the above `Provider` and `connect` and use them. diff --git a/website/versioned_docs/version-5.x/api/api.md b/website/versioned_docs/version-5.x/api/api.md new file mode 100644 index 000000000..cd25a8375 --- /dev/null +++ b/website/versioned_docs/version-5.x/api/api.md @@ -0,0 +1,51 @@ +--- +id: version-5.x-api +title: Api +sidebar_label: API +hide_title: true +original_id: api +--- + +# API + + +## Provider + +Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. + +If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +### Props + +* `store` (*[Redux Store](https://redux.js.org/api-reference/store)*): The single Redux store in your application. +* `children` (*ReactElement*) The root of your component hierarchy. + +### Example + +#### Vanilla React + +```jsx +ReactDOM.render( + + + , + rootEl +) +``` + +#### React Router + +```jsx +ReactDOM.render( + + + + + + + + , + document.getElementById('root') +) +``` + diff --git a/website/versioned_docs/version-5.x/api/connect-advanced.md b/website/versioned_docs/version-5.x/api/connect-advanced.md new file mode 100644 index 000000000..8828fc38e --- /dev/null +++ b/website/versioned_docs/version-5.x/api/connect-advanced.md @@ -0,0 +1,88 @@ +--- +id: version-5.x-connect-advanced +title: connectAdvanced +sidebar_label: connectAdvanced() +hide_title: true +original_id: connect-advanced +--- + +## connectAdvanced + +```js +connectAdvanced(selectorFactory, [connectOptions]) +``` + +Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. + +It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. + +### Arguments + +* `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(*Function*): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. + +* [`connectOptions`] *(Object)* If specified, further customizes the behavior of the connector. + + * [`getDisplayName`] *(Function)*: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` + + * [`methodName`] *(String)*: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` + + * [`renderCountProp`] *(String)*: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` + + * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` + + * [`storeKey`] *(String)*: the key of props/context to get the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + + * [`withRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` + + * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. + + + +### Returns + +A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. + +#### Static Properties + +* `WrappedComponent` *(Component)*: The original component class passed to `connectAdvanced(...)(Component)`. + +#### Static Methods + +All the original static methods of the component are hoisted. + +#### Instance Methods + +##### `getWrappedInstance(): ReactComponent` + +Returns the wrapped component instance. Only available if you pass `{ withRef: true }` as part of the `options` argument. + +### Remarks + +* Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. + +* `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. + + +#### Examples + +#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function selectorFactory(dispatch) { + let ownProps = {} + let result = {} + const actions = bindActionCreators(actionCreators, dispatch) + const addTodo = (text) => actions.addTodo(ownProps.userId, text) + return (nextState, nextOwnProps) => { + const todos = nextState.todos[nextOwnProps.userId] + const nextResult = { ...nextOwnProps, todos, addTodo } + ownProps = nextOwnProps + if (!shallowEqual(result, nextResult)) result = nextResult + return result + } +} +export default connectAdvanced(selectorFactory)(TodoApp) +``` diff --git a/website/versioned_docs/version-6.0.0/api.md b/website/versioned_docs/version-5.x/api/connect.md similarity index 72% rename from website/versioned_docs/version-6.0.0/api.md rename to website/versioned_docs/version-5.x/api/connect.md index 46455ebd4..b00ac2a12 100644 --- a/website/versioned_docs/version-6.0.0/api.md +++ b/website/versioned_docs/version-5.x/api/connect.md @@ -1,55 +1,10 @@ --- -id: version-6.0.0-api -title: Api -sidebar_label: API -hide_title: true -original_id: api +id: version-5.x-connect +title: Connect +sidebar_label: connect() +original_id: connect --- -# API - - -## Provider - -Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. - -If you *really* need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. - -### Props - -* `store` (*[Redux Store](https://redux.js.org/api-reference/store)*): The single Redux store in your application. -* `children` (*ReactElement*) The root of your component hierarchy. - -### Example - -#### Vanilla React - -```jsx -ReactDOM.render( - - - , - rootEl -) -``` - -#### React Router - -```jsx -ReactDOM.render( - - - - - - - - , - document.getElementById('root') -) -``` - - ## connect ``` @@ -88,6 +43,7 @@ It does not modify the component class passed to it; instead, it *returns* a new * [`areOwnPropsEqual`] *(Function)*: When pure, compares incoming props to its previous value. Default value: `shallowEqual` * [`areStatePropsEqual`] *(Function)*: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` * [`areMergedPropsEqual`] *(Function)*: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` + * [`storeKey`] *(String)*: The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` #### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps @@ -367,82 +323,3 @@ function mapDispatchToPropsFactory(initialState, initialProps) { export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp) ``` - -## connectAdvanced - -```js -connectAdvanced(selectorFactory, [connectOptions]) -``` - -Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. - -It does not modify the component class passed to it; instead, it *returns* a new, connected component class for you to use. - -### Arguments - -* `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(*Function*): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. - -* [`connectOptions`] *(Object)* If specified, further customizes the behavior of the connector. - - * [`getDisplayName`] *(Function)*: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` - - * [`methodName`] *(String)*: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` - - * [`renderCountProp`] *(String)*: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` - - * [`shouldHandleStateChanges`] *(Boolean)*: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` - - * [`forwardRef`] *(Boolean)*: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` - - * Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. - - - -### Returns - -A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. - -#### Static Properties - -* `WrappedComponent` *(Component)*: The original component class passed to `connectAdvanced(...)(Component)`. - -#### Static Methods - -All the original static methods of the component are hoisted. - -#### Instance Methods - -##### `getWrappedInstance(): ReactComponent` - -Returns the wrapped component instance. Only available if you pass `{ forwardRef: true }` as part of the `options` argument. - -### Remarks - -* Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. - -* `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. - - -#### Examples - -#### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action - -```js -import * as actionCreators from './actionCreators' -import { bindActionCreators } from 'redux' - -function selectorFactory(dispatch) { - let ownProps = {} - let result = {} - const actions = bindActionCreators(actionCreators, dispatch) - const addTodo = (text) => actions.addTodo(ownProps.userId, text) - return (nextState, nextOwnProps) => { - const todos = nextState.todos[nextOwnProps.userId] - const nextResult = { ...nextOwnProps, todos, addTodo } - ownProps = nextOwnProps - if (!shallowEqual(result, nextResult)) result = nextResult - return result - } -} -export default connectAdvanced(selectorFactory)(TodoApp) -``` \ No newline at end of file diff --git a/website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md b/website/versioned_docs/version-5.x/introduction/basic-tutorial.md similarity index 99% rename from website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md rename to website/versioned_docs/version-5.x/introduction/basic-tutorial.md index b82bd8658..785fc0cdd 100644 --- a/website/versioned_docs/version-5.1.1/introduction/basic-tutorial.md +++ b/website/versioned_docs/version-5.x/introduction/basic-tutorial.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-basic-tutorial +id: version-5.x-basic-tutorial title: Basic Tutorial hide_title: true sidebar_label: Basic Tutorial diff --git a/website/versioned_docs/version-5.1.1/introduction/quick-start.md b/website/versioned_docs/version-5.x/introduction/quick-start.md similarity index 97% rename from website/versioned_docs/version-5.1.1/introduction/quick-start.md rename to website/versioned_docs/version-5.x/introduction/quick-start.md index fe302e5f9..24823a0a1 100644 --- a/website/versioned_docs/version-5.1.1/introduction/quick-start.md +++ b/website/versioned_docs/version-5.x/introduction/quick-start.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-quick-start +id: version-5.x-quick-start title: Quick Start hide_title: true sidebar_label: Quick Start diff --git a/website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md b/website/versioned_docs/version-5.x/introduction/why-use-react-redux.md similarity index 99% rename from website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md rename to website/versioned_docs/version-5.x/introduction/why-use-react-redux.md index 917205616..cf5cd4aa8 100644 --- a/website/versioned_docs/version-5.1.1/introduction/why-use-react-redux.md +++ b/website/versioned_docs/version-5.x/introduction/why-use-react-redux.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-why-use-react-redux +id: version-5.x-why-use-react-redux title: Why Use React-Redux? hide_title: true sidebar_label: Why Use React-Redux? diff --git a/website/versioned_docs/version-5.1.1/troubleshooting.md b/website/versioned_docs/version-5.x/troubleshooting.md similarity index 99% rename from website/versioned_docs/version-5.1.1/troubleshooting.md rename to website/versioned_docs/version-5.x/troubleshooting.md index 950252bc4..83d662db5 100644 --- a/website/versioned_docs/version-5.1.1/troubleshooting.md +++ b/website/versioned_docs/version-5.x/troubleshooting.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-troubleshooting +id: version-5.x-troubleshooting title: Troubleshooting sidebar_label: Troubleshooting hide_title: true diff --git a/website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md b/website/versioned_docs/version-5.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md similarity index 99% rename from website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md rename to website/versioned_docs/version-5.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md index 31aaa0a08..b45c40e76 100644 --- a/website/versioned_docs/version-5.1.1/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md +++ b/website/versioned_docs/version-5.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-connect-mapdispatch +id: version-5.x-connect-mapdispatch title: Connect: Dispatching Actions with mapDispatchToProps hide_title: true sidebar_label: Connect: Dispatching Actions with mapDispatchToProps diff --git a/website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md b/website/versioned_docs/version-5.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md similarity index 99% rename from website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md rename to website/versioned_docs/version-5.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md index 08fae115a..0b6a2e8e3 100644 --- a/website/versioned_docs/version-5.1.1/using-react-redux/connect-extracting-data-with-mapStateToProps.md +++ b/website/versioned_docs/version-5.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md @@ -1,5 +1,5 @@ --- -id: version-5.1.1-connect-mapstate +id: version-5.x-connect-mapstate title: Connect: Extracting Data with mapStateToProps hide_title: true sidebar_label: Connect: Extracting Data with mapStateToProps diff --git a/website/versioned_sidebars/version-5.1.1-sidebars.json b/website/versioned_sidebars/version-5.1.1-sidebars.json deleted file mode 100644 index d2b32e3b2..000000000 --- a/website/versioned_sidebars/version-5.1.1-sidebars.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version-5.1.1-docs": { - "Introduction": [ - "version-5.1.1-introduction/quick-start", - "version-5.1.1-introduction/basic-tutorial", - "version-5.1.1-introduction/why-use-react-redux" - ], - "Using React-Redux": [ - "version-5.1.1-using-react-redux/connect-mapstate", - "version-5.1.1-using-react-redux/connect-mapdispatch" - ], - "API Reference": [ - "version-5.1.1-api", - "version-5.1.1-api/provider" - ], - "Guides": [ - "version-5.1.1-troubleshooting" - ] - } -} diff --git a/website/versioned_sidebars/version-5.x-sidebars.json b/website/versioned_sidebars/version-5.x-sidebars.json new file mode 100644 index 000000000..07aabf72e --- /dev/null +++ b/website/versioned_sidebars/version-5.x-sidebars.json @@ -0,0 +1,22 @@ +{ + "version-5.x-docs": { + "Introduction": [ + "version-5.x-introduction/quick-start", + "version-5.x-introduction/basic-tutorial", + "version-5.x-introduction/why-use-react-redux" + ], + "Using React-Redux": [ + "version-5.x-using-react-redux/connect-mapstate", + "version-5.x-using-react-redux/connect-mapdispatch" + ], + "API Reference": [ + "version-5.x-api", + "version-5.x-api/connect", + "version-5.x-api/connect-advanced", + "version-5.x-api/provider" + ], + "Guides": [ + "version-5.x-troubleshooting" + ] + } +} diff --git a/website/versions.json b/website/versions.json index e2c5a88ab..b2e70a688 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,4 +1,3 @@ [ - "6.0.0", - "5.1.1" + "5.x" ] From 69f501472cade73bda0c2f51aa3a0e3ba6e63e27 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Sun, 7 Apr 2019 12:59:25 +0800 Subject: [PATCH 4/5] Cast v6.x versioned docs --- .../version-6.x/api/Provider.md | 101 +++ .../version-6.x/api/connect-advanced.md | 87 +++ .../versioned_docs/version-6.x/api/connect.md | 628 ++++++++++++++++++ .../introduction/basic-tutorial.md | 459 +++++++++++++ .../version-6.x/introduction/quick-start.md | 84 +++ .../introduction/why-use-react-redux.md | 91 +++ .../version-6.x/troubleshooting.md | 95 +++ .../using-react-redux/accessing-store.md | 145 ++++ ...atching-actions-with-mapDispatchToProps.md | 410 ++++++++++++ ...ct-extracting-data-with-mapStateToProps.md | 229 +++++++ .../version-6.x-sidebars.json | 22 + website/versions.json | 1 + 12 files changed, 2352 insertions(+) create mode 100644 website/versioned_docs/version-6.x/api/Provider.md create mode 100644 website/versioned_docs/version-6.x/api/connect-advanced.md create mode 100644 website/versioned_docs/version-6.x/api/connect.md create mode 100644 website/versioned_docs/version-6.x/introduction/basic-tutorial.md create mode 100644 website/versioned_docs/version-6.x/introduction/quick-start.md create mode 100644 website/versioned_docs/version-6.x/introduction/why-use-react-redux.md create mode 100644 website/versioned_docs/version-6.x/troubleshooting.md create mode 100644 website/versioned_docs/version-6.x/using-react-redux/accessing-store.md create mode 100644 website/versioned_docs/version-6.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md create mode 100644 website/versioned_docs/version-6.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md create mode 100644 website/versioned_sidebars/version-6.x-sidebars.json diff --git a/website/versioned_docs/version-6.x/api/Provider.md b/website/versioned_docs/version-6.x/api/Provider.md new file mode 100644 index 000000000..73075bc28 --- /dev/null +++ b/website/versioned_docs/version-6.x/api/Provider.md @@ -0,0 +1,101 @@ +--- +id: version-6.x-provider +title: Provider +sidebar_label: Provider +hide_title: true +original_id: provider +--- + +# `Provider` + +## Overview + +The `` makes the Redux `store` available to any nested components that have been wrapped in the `connect()` function. + +Since any React component in a React Redux app can be connected, most applications will render a `` at the top level, with the entire app’s component tree inside of it. + +Normally, you can’t use a connected component unless it is nested inside of a ``. + +### Props + +`store` ([Redux Store](https://redux.js.org/api/store)) +The single Redux `store` in your application. + +`children` (ReactElement) +The root of your component hierarchy. + +`context` +You may provide a context instance. If you do so, you will need to provide the same context instance to all of your connected components as well. Failure to provide the correct context results in runtime error: + +> Invariant Violation +> +> Could not find "store" in the context of "Connect(MyComponent)". Either wrap the root component in a ``, or pass a custom React context provider to `` and the corresponding React context consumer to Connect(Todo) in connect options. + +**Note:** You do not need to provide custom context in order to access the store. +React Redux exports the context instance it uses by default so that you can access the store by: + +```js +import { ReactReduxContext } from 'react-redux' + +// in your connected component +render() { + return ( + + {({ store }) => { + // do something with the store here + }} + + ) +} +``` + +### Example Usage + +In the example below, the `` component is our root-level component. This means it’s at the very top of our component hierarchy. + +**Vanilla React Example** + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Provider } from 'react-redux' + +import { App } from './App' +import createStore from './createReduxStore' + +const store = createStore() + +ReactDOM.render( + + + , + document.getElementById('root') +) +``` + +**Usage with React Router** + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Provider } from 'react-redux' +import { Router, Route } from 'react-router-dom' + +import { App } from './App' +import { Foo } from './Foo' +import { Bar } from './Bar' +import createStore from './createReduxStore' + +const store = createStore() + +ReactDOM.render( + + + + + + + , + document.getElementById('root') +) +``` diff --git a/website/versioned_docs/version-6.x/api/connect-advanced.md b/website/versioned_docs/version-6.x/api/connect-advanced.md new file mode 100644 index 000000000..f6029bcec --- /dev/null +++ b/website/versioned_docs/version-6.x/api/connect-advanced.md @@ -0,0 +1,87 @@ +--- +id: version-6.x-connect-advanced +title: connectAdvanced +sidebar_label: connectAdvanced() +hide_title: true +original_id: connect-advanced +--- + +# `connectAdvanced()` + +```js +connectAdvanced(selectorFactory, connectOptions?) +``` + +Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. + +It does not modify the component class passed to it; instead, it _returns_ a new, connected component class for you to use. + +Most applications will not need to use this, as the default behavior in `connect` is intended to work for most use cases. + +> Note: `connectAdvanced` was added in version 5.0, and `connect` was reimplemented as a specific set of parameters to `connectAdvanced`. + +## Arguments + +- `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(_Function_): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. + +- [`connectOptions`] _(Object)_ If specified, further customizes the behavior of the connector. + + - [`getDisplayName`] _(Function)_: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` + + - [`methodName`] _(String)_: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` + + - [`renderCountProp`] _(String)_: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` + + - [`shouldHandleStateChanges`] _(Boolean)_: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` + + - [`forwardRef`] _(Boolean)_: If true, adding a ref to the connected wrapper component will actually return the instance of the wrapped component. + + - Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. + + + +## Returns + +A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. + +### Static Properties + +- `WrappedComponent` _(Component)_: The original component class passed to `connectAdvanced(...)(Component)`. + +### Static Methods + +All the original static methods of the component are hoisted. + +## Remarks + +- Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. + +- `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. + + + +### Examples + +### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from './actionCreators' +import { bindActionCreators } from 'redux' + +function selectorFactory(dispatch) { + let ownProps = {} + let result = {} + + const actions = bindActionCreators(actionCreators, dispatch) + const addTodo = text => actions.addTodo(ownProps.userId, text) + + return (nextState, nextOwnProps) => { + const todos = nextState.todos[nextOwnProps.userId] + const nextResult = { ...nextOwnProps, todos, addTodo } + ownProps = nextOwnProps + if (!shallowEqual(result, nextResult)) result = nextResult + return result + } +} +export default connectAdvanced(selectorFactory)(TodoApp) +``` diff --git a/website/versioned_docs/version-6.x/api/connect.md b/website/versioned_docs/version-6.x/api/connect.md new file mode 100644 index 000000000..1b30310d9 --- /dev/null +++ b/website/versioned_docs/version-6.x/api/connect.md @@ -0,0 +1,628 @@ +--- +id: version-6.x-connect +title: Connect +sidebar_label: connect() +hide_title: true +original_id: connect +--- + +# `connect()` + +## Overview + +The `connect()` function connects a React component to a Redux store. + +It provides its connected component with the pieces of the data it needs from the store, and the functions it can use to dispatch actions to the store. + +It does not modify the component class passed to it; instead, it returns a new, connected component class that wraps the component you passed in. + +```js +function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?) +``` + +The `mapStateToProps` and `mapDispatchToProps` deals with your Redux store’s `state` and `dispatch`, respectively. `state` and `dispatch` will be supplied to your `mapStateToProps` or `mapDispatchToProps` functions as the first argument. + +The returns of `mapStateToProps` and `mapDispatchToProps` are referred to internally as `stateProps` and `dispatchProps`, respectively. They will be supplied to `mergeProps`, if defined, as the first and the second argument, where the third argument will be `ownProps`. The combined result, commonly referred to as `mergedProps`, will then be supplied to your connected component. + +## `connect()` Parameters + +`connect` accepts four different parameters, all optional. By convention, they are called: + +1. `mapStateToProps?: Function` +2. `mapDispatchToProps?: Function | Object` +3. `mergeProps?: Function` +4. `options?: Object` + +### `mapStateToProps?: (state, ownProps?) => Object` + +If a `mapStateToProps` function is specified, the new wrapper component will subscribe to Redux store updates. This means that any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into the wrapped component’s props. If you don't want to subscribe to store updates, pass `null` or `undefined` in place of `mapStateToProps`. + +#### Parameters + +1. `state: Object` +2. `ownProps?: Object` + +A `mapStateToProps` function takes a maximum of two parameters. The number of declared function parameters (a.k.a. arity) affects when it will be called. This also determines whether the function will receive ownProps. See notes [here](#the-arity-of-maptoprops-functions). + +##### `state` + +If your `mapStateToProps` function is declared as taking one parameter, it will be called whenever the store state changes, and given the store state as the only parameter. + +```js +const mapStateToProps = state => ({ todos: state.todos }) +``` + +##### `ownProps` + +If your `mapStateToProps` function is declared as taking two parameters, it will be called whenever the store state changes _or_ when the wrapper component receives new props (based on shallow equality comparisons). It will be given the store state as the first parameter, and the wrapper component's props as the second parameter. + +The second parameter is normally referred to as `ownProps` by convention. + +```js +const mapStateToProps = (state, ownProps) => ({ + todo: state.todos[ownProps.id] +}) +``` + +#### Returns + +Your `mapStateToProps` functions are expected to return an object. This object, normally referred to as `stateProps`, will be merged as props to your connected component. If you define `mergeProps`, it will be supplied as the first parameter to `mergeProps`. + +The return of the `mapStateToProps` determine whether the connected component will re-render (details [here](../using-react-redux/connect-mapstate#return-values-determine-if-your-component-re-renders)). + +For more details on recommended usage of `mapStateToProps`, please refer to [our guide on using `mapStateToProps`](../using-react-redux/connect-mapstate). + +> You may define `mapStateToProps` and `mapDispatchToProps` as a factory function, i.e., you return a function instead of an object. In this case your returned function will be treated as the real `mapStateToProps` or `mapDispatchToProps`, and be called in subsequent calls. You may see notes on [Factory Functions](#factory-functions) or our guide on performance optimizations. + +### `mapDispatchToProps?: Object | (dispatch, ownProps?) => Object` + +Conventionally called `mapDispatchToProps`, this second parameter to `connect()` may either be an object, a function, or not supplied. + +Your component will receive `dispatch` by default, i.e., when you do not supply a second parameter to `connect()`: + +```js +// do not pass `mapDispatchToProps` +connect()(MyComponent) +connect(mapState)(MyComponent) +connect( + mapState, + null, + mergeProps, + options +)(MyComponent) +``` + +If you define a `mapDispatchToProps` as a function, it will be called with a maximum of two parameters. + +#### Parameters + +1. `dispatch: Function` +2. `ownProps?: Object` + +##### `dispatch` + +If your `mapDispatchToProps` is declared as a function taking one parameter, it will be given the `dispatch` of your `store`. + +```js +const mapDispatchToProps = dispatch => { + return { + // dispatching plain actions + increment: () => dispatch({ type: 'INCREMENT' }), + decrement: () => dispatch({ type: 'DECREMENT' }), + reset: () => dispatch({ type: 'RESET' }) + } +} +``` + +##### `ownProps` + +If your `mapDispatchToProps` function is declared as taking two parameters, it will be called with `dispatch` as the first parameter and the props passed to the wrapper component as the second parameter, and will be re-invoked whenever the connected component receives new props. + +The second parameter is normally referred to as `ownProps` by convention. + +```js +// binds on component re-rendering + + + ) + } +} + +export default connect( + null, + { addTodo } +)(AddTodo) +``` + +Now our `` is connected to the store. When we add a todo it would dispatch an action to change the store. We are not seeing it in the app because the other components are not connected yet. If you have the Redux DevTools Extension hooked up, you should see the action being dispatched: + +![](https://i.imgur.com/kHvkqhI.png) + +You should also see that the store has changed accordingly: + +![](https://i.imgur.com/yx27RVC.png) + +The `` component is responsible for rendering the list of todos. Therefore, it needs to read data from the store. We enable it by calling `connect` with the `mapStateToProps` parameter, a function describing which part of the data we need from the store. + +Our `` component takes the todo item as props. We have this information from the `byIds` field of the `todos`. However, we also need the information from the `allIds` field of the store indicating which todos and in what order they should be rendered. Our `mapStateToProps` function may look like this: + +```js +// components/TodoList.js + +// ...other imports +import { connect } from "react-redux"; + +const TodoList = // ... UI component implementation + +const mapStateToProps = state => { + const { byIds, allIds } = state.todos || {}; + const todos = + allIds && allIds.length + ? allIds.map(id => (byIds ? { ...byIds[id], id } : null)) + : null; + return { todos }; +}; + +export default connect(mapStateToProps)(TodoList); +``` + +Luckily we have a selector that does exactly this. We may simply import the selector and use it here. + +```js +// redux/selectors.js + +export const getTodosState = store => store.todos + +export const getTodoList = store => + getTodosState(store) ? getTodosState(store).allIds : [] + +export const getTodoById = (store, id) => + getTodosState(store) ? { ...getTodosState(store).byIds[id], id } : {} + +export const getTodos = store => + getTodoList(store).map(id => getTodoById(store, id)) +``` + +```js +// components/TodoList.js + +// ...other imports +import { connect } from "react-redux"; +import { getTodos } from "../redux/selectors"; + +const TodoList = // ... UI component implementation + +export default connect(state => ({ todos: getTodos(state) }))(TodoList); +``` + +We recommend encapsulating any complex lookups or computations of data in selector functions. In addition, you can further optimize the performance by using [Reselect](https://github.com/reduxjs/reselect) to write “memoized” selectors that can skip unnecessary work. (See [the Redux docs page on Computing Derived Data](https://redux.js.org/recipes/computingderiveddata#sharing-selectors-across-multiple-components) and the blog post [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) for more information on why and how to use selector functions.) + +Now that our `` is connected to the store. It should receive the list of todos, map over them, and pass each todo to the `` component. `` will in turn render them to the screen. Now try adding a todo. It should come up on our todo list! + +![](https://i.imgur.com/N68xvrG.png) + +We will connect more components. Before we do this, let’s pause and learn a bit more about `connect` first. + +### Common ways of calling `connect` + +Depending on what kind of components you are working with, there are different ways of calling `connect` , with the most common ones summarized as below: + +| | Do Not Subscribe to the Store | Subscribe to the Store | +| ----------------------------- | ---------------------------------------------- | --------------------------------------------------------- | +| Do Not Inject Action Creators | `connect()(Component)` | `connect(mapStateToProps)(Component)` | +| Inject Action Creators | `connect(null, mapDispatchToProps)(Component)` | `connect(mapStateToProps, mapDispatchToProps)(Component)` | + +#### Do not subscribe to the store and do not inject action creators + +If you call `connect` without providing any arguments, your component will: + +- _not_ re-render when the store changes +- receive `props.dispatch` that you may use to manually dispatch action + +```js +// ... Component +export default connect()(Component) // Component will receive `dispatch` (just like our !) +``` + +#### Subscribe to the store and do not inject action creators + +If you call `connect` with only `mapStateToProps`, your component will: + +- subscribe to the values that `mapStateToProps` extracts from the store, and re-render only when those values have changed +- receive `props.dispatch` that you may use to manually dispatch action + +```js +// ... Component +const mapStateToProps = state => state.partOfState +export default connect(mapStateToProps)(Component) +``` + +#### Do not subscribe to the store and inject action creators + +If you call `connect` with only `mapDispatchToProps`, your component will: + +- _not_ re-render when the store changes +- receive each of the action creators you inject with `mapDispatchToProps` as props and automatically dispatch the actions upon being called + +```js +import { addTodo } from './actionCreators' +// ... Component +export default connect( + null, + { addTodo } +)(Component) +``` + +#### Subscribe to the store and inject action creators + +If you call `connect` with both `mapStateToProps` and `mapDispatchToProps`, your component will: + +- subscribe to the values that `mapStateToProps` extracts from the store, and re-render only when those values have changed +- receive all of the action creators you inject with `mapDispatchToProps` as props and automatically dispatch the actions upon being called. + +```js +import * as actionCreators from './actionCreators' +// ... Component +const mapStateToProps = state => state.partOfState +export default connect( + mapStateToProps, + actionCreators +)(Component) +``` + +These four cases cover the most basic usages of `connect`. To read more about `connect`, continue reading our [API section](../api/connect.md) that explains it in more detail. + + + +--- + +Now let’s connect the rest of our ``. + +How should we implement the interaction of toggling todos? A keen reader might already have an answer. If you have your environment set up and have followed through up until this point, now is a good time to leave it aside and implement the feature by yourself. There would be no surprise that we connect our `` to dispatch `toggleTodo` in a similar way: + +```js +// components/Todo.js + +// ... other imports +import { connect } from "react-redux"; +import { toggleTodo } from "../redux/actions"; + +const Todo = // ... component implementation + +export default connect( + null, + { toggleTodo } +)(Todo); +``` + +Now our todo’s can be toggled complete. We’re almost there! + +![](https://i.imgur.com/4UBXYtj.png) + +Finally, let’s implement our `VisibilityFilters` feature. + +The `` component needs to be able to read from the store which filter is currently active, and dispatch actions to the store. Therefore, we need to pass both a `mapStateToProps` and `mapDispatchToProps`. The `mapStateToProps` here can be a simple accessor of the `visibilityFilter` state. And the `mapDispatchToProps` will contain the `setFilter` action creator. + +```js +// components/VisibilityFilters.js + +// ... other imports +import { connect } from "react-redux"; +import { setFilter } from "../redux/actions"; + +const VisibilityFilters = // ... component implementation + +const mapStateToProps = state => { + return { activeFilter: state.visibilityFilter }; +}; +export default connect( + mapStateToProps, + { setFilter } +)(VisibilityFilters); +``` + +Meanwhile, we also need to update our `` component to filter todos according to the active filter. Previously the `mapStateToProps` we passed to the `` `connect` function call was simply the selector that selects the whole list of todos. Let’s write another selector to help filtering todos by their status. + +```js +// redux/selectors.js + +// ... other selectors +export const getTodosByVisibilityFilter = (store, visibilityFilter) => { + const allTodos = getTodos(store) + switch (visibilityFilter) { + case VISIBILITY_FILTERS.COMPLETED: + return allTodos.filter(todo => todo.completed) + case VISIBILITY_FILTERS.INCOMPLETE: + return allTodos.filter(todo => !todo.completed) + case VISIBILITY_FILTERS.ALL: + default: + return allTodos + } +} +``` + +And connecting to the store with the help of the selector: + +```js +// components/TodoList.js + +// ... + +const mapStateToProps = state => { + const { visibilityFilter } = state + const todos = getTodosByVisibilityFilter(state, visibilityFilter) + return { todos } +} + +export default connect(mapStateToProps)(TodoList) +``` + +Now we've finished a very simple example of a todo app with React Redux. All our components are connected! Isn't that nice? 🎉🎊 + +![](https://i.imgur.com/ONqer2R.png) + +## Links + +- [Usage with React](https://redux.js.org/basics/usagewithreact) +- [Using the React Redux Bindings](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/react-redux.html) +- [Higher Order Components in Depth](https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e) +- [Computing Derived Data](https://redux.js.org/recipes/computingderiveddata#sharing-selectors-across-multiple-components) +- [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) + +## Get More Help + +- [Reactiflux](https://www.reactiflux.com) Redux channel +- [StackOverflow](https://stackoverflow.com/questions/tagged/react-redux) +- [GitHub Issues](https://github.com/reduxjs/react-redux/issues/) diff --git a/website/versioned_docs/version-6.x/introduction/quick-start.md b/website/versioned_docs/version-6.x/introduction/quick-start.md new file mode 100644 index 000000000..176a856a1 --- /dev/null +++ b/website/versioned_docs/version-6.x/introduction/quick-start.md @@ -0,0 +1,84 @@ +--- +id: version-6.x-quick-start +title: Quick Start +hide_title: true +sidebar_label: Quick Start +original_id: quick-start +--- + +# Quick Start + +[React Redux](https://github.com/reduxjs/react-redux) is the official [React](https://reactjs.org/) binding for [Redux](https://redux.js.org/). It lets your React components read data from a Redux store, and dispatch actions to the store to update data. + +## Installation + +React Redux 6.x requires **React 16.4 or later.** + +To use React Redux with your React app: + +```bash +npm install react-redux +``` + +or + +```bash +yarn add react-redux +``` + +You'll also need to [install Redux](https://redux-docs.netlify.com/introduction/installation) and [set up a Redux store](https://redux-docs.netlify.com/recipes/configuring-your-store) in your app. + +## `Provider` + +React Redux provides ``, which makes the Redux store available to the rest of your app: + +```js +import React from 'react' +import ReactDOM from 'react-dom' + +import { Provider } from 'react-redux' +import store from './store' + +import App from './App' + +const rootElement = document.getElementById('root') +ReactDOM.render( + + + , + rootElement +) +``` + +## `connect()` + +React Redux provides a `connect` function for you to connect your component to the store. + +Normally, you’ll call `connect` in this way: + +```js +import { connect } from 'react-redux' +import { increment, decrement, reset } from './actionCreators' + +// const Counter = ... + +const mapStateToProps = (state /*, ownProps*/) => { + return { + counter: state.counter + } +} + +const mapDispatchToProps = { increment, decrement, reset } + +export default connect( + mapStateToProps, + mapDispatchToProps +)(Counter) +``` + + +## Help and Discussion + +The **[#redux channel](https://discord.gg/0ZcbPKXt5bZ6au5t)** of the **[Reactiflux Discord community](http://www.reactiflux.com)** is our official resource for all questions related to learning and using Redux. Reactiflux is a great place to hang out, ask questions, and learn - come join us! + +You can also ask questions on [Stack Overflow](https://stackoverflow.com) using the **[#redux tag](https://stackoverflow.com/questions/tagged/redux)**. diff --git a/website/versioned_docs/version-6.x/introduction/why-use-react-redux.md b/website/versioned_docs/version-6.x/introduction/why-use-react-redux.md new file mode 100644 index 000000000..266e22bda --- /dev/null +++ b/website/versioned_docs/version-6.x/introduction/why-use-react-redux.md @@ -0,0 +1,91 @@ +--- +id: version-6.x-why-use-react-redux +title: Why Use React Redux? +hide_title: true +sidebar_label: Why Use React Redux? +original_id: why-use-react-redux +--- + +# Why Use React Redux? + +Redux itself is a standalone library that can be used with any UI layer or framework, including React, Angular, Vue, Ember, and vanilla JS. Although Redux and React are commonly used together, they are independent of each other. + +If you are using Redux with any kind of UI framework, you will normally use a "UI binding" library to tie Redux together with your UI framework, rather than directly interacting with the store from your UI code. + +**React Redux is the official Redux UI binding library for React**. If you are using Redux and React together, you should also use React Redux to bind these two libraries. + +To understand why you should use React Redux, it may help to understand what a "UI binding library" does. + +> **Note**: If you have questions about whether you should use Redux in general, please see these articles for discussion of when and why you might want to use Redux, and how it's intended to be used: +> +> - [Redux docs: Motivation](https://redux.js.org/introduction/motivation) +> - [Redux docs: FAQ - When should I use Redux?](https://redux.js.org/faq/general#when-should-i-use-redux) +> - [You Might Not Need Redux](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367) +> - [Idiomatic Redux: The Tao of Redux, Part 1 - Implementation and Intent](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/) + +## Integrating Redux with a UI + +Using Redux with _any_ UI layer requires [the same consistent set of steps](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html#/4): + +1. Create a Redux store +2. Subscribe to updates +3. Inside the subscription callback: + 1. Get the current store state + 2. Extract the data needed by this piece of UI + 3. Update the UI with the data +4. If necessary, render the UI with initial state +5. Respond to UI inputs by dispatching Redux actions + +While it is possible to write this logic by hand, doing so would become very repetitive. In addition, optimizing UI performance would require complicated logic. + +The process of subscribing to the store, checking for updated data, and triggering a re-render can be made more generic and reusable. **A UI binding library like React Redux handles the store interaction logic, so you don't have to write that code yourself.** + +> **Note**: For a deeper look at how React Redux works internally and how it handles the store interaction for you, see **[Idiomatic Redux: The History and Implementation of React Redux](https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/)**. + +## Reasons to Use React Redux + +### It is the Official Redux UI Bindings for React + +While Redux can be used with any UI layer, it was originally designed and intended for use with React. There are [UI binding layers for many other frameworks](https://redux.js.org/introduction/ecosystem#library-integration-and-bindings), but React Redux is maintained directly by the Redux team. + +As the offical Redux binding for React, React Redux is kept up-to-date with any API changes from either library, to ensure that your React components behave as expected. Its intended usage adopts the design principles of React - writing declarative components. + +### It Encourages Good React Architecture + +React components are a lot like functions. While it's possible to write all your code in a single function, it's usually better to split that logic into smaller functions that each handle a specific task, making them easier to understand. + +Similarly, while you can write large React components that handle many different tasks, it's usually better to split up components based on responsibilities. In particular, it is common to have "container" components that are responsible for collecting and managing some kind of data, and "presentational" components that simply display UI based on whatever data they've received as props. + +**The React Redux `connect` function generates "container" wrapper components that handle the process of interacting with the store for you**. That way, your own components can focus on other tasks, whether it be collecting other data, or just displaying a piece of the UI. In addition, **`connect` abstracts away the question of _which_ store is being used, making your own components more reusable**. + +As a general architectural principle, **we want to keep our own components "unaware" of Redux**. They should simply receive data and functions as props, just like any other React component. This ultimately makes it easier to test and reuse your own components. + +### It Implements Performance Optimizations For You + +React is generally fast, but by default any updates to a component will cause React to re-render all of the components inside that part of the component tree. This does require work, and if the data for a given component hasn't changed, then re-rendering is likely some wasted effort because the requested UI output would be the same. + +If performance is a concern, the best way to improve performance is to skip unnecessary re-renders, so that components only re-render when their data has actually changed. **React Redux implements many performance optimizations internally, so that your own component only re-renders when it actually needs to.** + +In addition, by connecting multiple components in your React component tree, you can ensure that each connected component only extracts the specific pieces of data from the store state that are needed by that component. This means that your own component will need to re-render less often, because most of the time those specific pieces of data haven't changed. + +### Community Support + +As the official binding library for React and Redux, React Redux has a large community of users. This makes it easier to ask for help, learn about best practices, use libraries that build on top of React Redux, and reuse your knowledge across different applications. + +## Links and References + +### Understanding React Redux + +- [Idiomatic Redux: The History and Implementation of React Redux](https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/) +- [`connect.js` Explained](https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e) +- [Redux Fundamentals workshop slides](https://blog.isquaredsoftware.com/2018/06/redux-fundamentals-workshop-slides/) + - [UI Layer Integration](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html) + - [Using React Redux](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/react-redux.html) + +### Community Resources + +- Discord channel: [#redux on Reactiflux](https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e) ([Reactiflux invite link](https://reactiflux.com)) +- Stack Overflow topics: [Redux](https://stackoverflow.com/questions/tagged/redux), [React Redux](https://stackoverflow.com/questions/tagged/redux) +- Reddit: [/r/reactjs](https://www.reddit.com/r/reactjs/), [/r/reduxjs](https://www.reddit.com/r/reduxjs/) +- Github issues (bug reports and feature requests): https://github.com/reduxjs/react-redux/issues +- Tutorials, articles, and further resources: [React/Redux Links](https://www.reddit.com/r/reduxjs/) diff --git a/website/versioned_docs/version-6.x/troubleshooting.md b/website/versioned_docs/version-6.x/troubleshooting.md new file mode 100644 index 000000000..774ac3bef --- /dev/null +++ b/website/versioned_docs/version-6.x/troubleshooting.md @@ -0,0 +1,95 @@ +--- +id: version-6.x-troubleshooting +title: Troubleshooting +sidebar_label: Troubleshooting +hide_title: true +original_id: troubleshooting +--- + +## Troubleshooting + +Make sure to check out [Troubleshooting Redux](http://redux.js.org/docs/Troubleshooting.html) first. + +### I'm getting the following alert: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead. + +This warning is shown when using react 15.5.\*. Basically, now it's just a warning, but in react16 the application might break. the PropTypes should now be imported from 'prop-types' package, and not from the react package. + +Update to the latest version of react-redux. + +### My views aren’t updating! + +See the link above. +In short, + +- Reducers should never mutate state, they must return new objects, or React Redux won’t see the updates. +- Make sure you either bind action creators with the `mapDispatchToProps` argument to `connect()` or with the `bindActionCreators()` method, or that you manually call `dispatch()`. Just calling your `MyActionCreators.addTodo()` function won’t work because it just _returns_ an action, but does not _dispatch_ it. + +### My views aren’t updating on route change with React Router 0.13 + +If you’re using React Router 0.13, you might [bump into this problem](https://github.com/reduxjs/react-redux/issues/43). The solution is simple: whenever you use `` or the `Handler` provided by `Router.run`, pass the router state to it. + +Root view: + +```jsx +Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { + // note "routerState" here + ReactDOM.render( + + {/* note "routerState" here */} + + , + document.getElementById('root') + ) +}) +``` + +Nested view: + +```js +render() { + // Keep passing it down + return +} +``` + +Conveniently, this gives your components access to the router state! +You can also upgrade to React Router 1.0 which shouldn’t have this problem. (Let us know if it does!) + +### My views aren’t updating when something changes outside of Redux + +If your views depend on global state or [React “context”](http://facebook.github.io/react/docs/context.html), you might find that views decorated with `connect()` will fail to update. + +> This is because `connect()` implements [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) by default, assuming that your component will produce the same results given the same props and state. This is a similar concept to React’s [PureRenderMixin](https://facebook.github.io/react/docs/pure-render-mixin.html). + +The _best_ solution to this is to make sure that your components are pure and pass any external state to them via props. This will ensure that your views do not re-render unless they actually need to re-render and will greatly speed up your application. + +If that’s not practical for whatever reason (for example, if you’re using a library that depends heavily on React context), you may pass the `pure: false` option to `connect()`: + +```js +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect( + mapStateToProps, + null, + null, + { + pure: false + } +)(TodoApp) +``` + +This will remove the assumption that `TodoApp` is pure and cause it to update whenever its parent component renders. Note that this will make your application less performant, so only do this if you have no other option. + +### Could not find "store" in either the context or props + +If you have context issues, + +1. [Make sure you don’t have a duplicate instance of React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375) on the page. +2. Make sure you didn’t forget to wrap your root or some other ancestor component in [``](#provider-store). +3. Make sure you’re running the latest versions of React and React Redux. + +### Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you’re trying to add a ref to a component that doesn’t have an owner + +If you’re using React for web, this usually means you have a [duplicate React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375). Follow the linked instructions to fix this. diff --git a/website/versioned_docs/version-6.x/using-react-redux/accessing-store.md b/website/versioned_docs/version-6.x/using-react-redux/accessing-store.md new file mode 100644 index 000000000..c295c4c0e --- /dev/null +++ b/website/versioned_docs/version-6.x/using-react-redux/accessing-store.md @@ -0,0 +1,145 @@ +--- +id: version-6.x-accessing-store +title: Accessing the Store +hide_title: true +sidebar_label: Accessing the Store +original_id: accessing-store +--- + +# Accessing the Store + +React Redux provides APIs that allow your components to dispatch actions and subscribe to data updates from the store. + +As part of that, React Redux abstracts away the details of which store you are using, and the exact details of how that +store interaction is handled. In typical usage, your own components should never need to care about those details, and +won't ever reference the store directly. React Redux also internally handles the details of how the store and state are +propagated to connected components, so that this works as expected by default. + +However, there may be certain use cases where you may need to customize how the store and state are propagated to +connected components, or access the store directly. Here are some examples of how to do this. + +## Understanding Context Usage + +Internally, React Redux uses [React's "context" feature](https://reactjs.org/docs/context.html) to make the +Redux store accessible to deeply nested connected components. As of React Redux version 6, this is normally handled +by a single default context object instance generated by `React.createContext()`, called `ReactReduxContext`. + +React Redux's `` component uses `` to put the Redux store and the current store +state into context, and `connect` uses `` to read those values and handle updates. + +## Providing Custom Context + +Instead of using the default context instance from React Redux, you may supply your own custom context instance. + +```js + + + +``` + +If you supply a custom context, React Redux will use that context instance instead of the one it creates and exports by default. + +After you’ve supplied the custom context to ``, you will need to supply this context instance to all of your connected components that are expected to connect to the same store: + +```js +// You can pass the context as an option to connect +export default connect( + mapState, + mapDispatch, + null, + { context: MyContext } +)(MyComponent); + +// or, call connect as normal to start +const ConnectedComponent = connect( + mapState, + mapDispatch +)(MyComponent); + +// Later, pass the custom context as a prop to the connected component + +``` + +The following runtime error occurs when React Redux does not find a store in the context it is looking. For example: + +- You provided a custom context instance to ``, but did not provide the same instance (or did not provide any) to your connected components. +- You provided a custom context to your connected component, but did not provide the same instance (or did not provide any) to ``. + +> Invariant Violation +> +> Could not find "store" in the context of "Connect(MyComponent)". Either wrap the root component in a ``, or pass a custom React context provider to `` and the corresponding React context consumer to Connect(Todo) in connect options. + +## Multiple Stores + +[Redux was designed to use a single store](https://redux.js.org/api/store#a-note-for-flux-users). +However, if you are in an unavoidable position of needing to use multiple stores, with v6 you may do so by providing (multiple) custom contexts. +This also provides a natural isolation of the stores as they live in separate context instances. + +```js +// a naive example +const ContextA = React.createContext(); +const ContextB = React.createContext(); + +// assuming reducerA and reducerB are proper reducer functions +const storeA = createStore(reducerA); +const storeB = createStore(reducerB); + +// supply the context instances to Provider +function App() { + return ( + + + + + + ); +} + +// fetch the corresponding store with connected components +// you need to use the correct context +connect(mapStateA, null, null, { context: ContextA })(MyComponentA) + +// You may also pass the alternate context instance directly to the connected component instead + + +// it is possible to chain connect() +// in this case MyComponent will receive merged props from both stores +compose( + connect(mapStateA, null, null, { context: ContextA }), + connect(mapStateB, null, null, { context: ContextB }) +)(MyComponent); +``` + +## Using `ReactReduxContext` Directly + +In rare cases, you may need to access the Redux store directly in your own components. This can be done by rendering +the appropriate context consumer yourself, and accessing the `store` field out of the context value. + +> **Note**: This is **_not_ considered part of the React Redux public API, and may break without notice**. We do recognize +> that the community has use cases where this is necessary, and will try to make it possible for users to build additional +> functionality on top of React Redux, but our specific use of context is considered an implementation detail. +> If you have additional use cases that are not sufficiently covered by the current APIs, please file an issue to discuss +> possible API improvements. + +```js +import { ReactReduxContext } from 'react-redux' + +// in your connected component +function MyConnectedComponent() { + return ( + + {({ store }) => { + // do something useful with the store, like passing it to a child + // component where it can be used in lifecycle methods + }} + + ); +} +``` + +## Further Resources + +- CodeSandbox example: [A reading list app with theme using a separate store](https://codesandbox.io/s/92pm9n2kl4), implemented by providing (multiple) custom context(s). +- Related issues: + - [#1132: Update docs for using a different store key](https://github.com/reduxjs/react-redux/issues/1132) + - [#1126: `` misses state changes that occur between when its constructor runs and when it mounts](https://github.com/reduxjs/react-redux/issues/1126) diff --git a/website/versioned_docs/version-6.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md b/website/versioned_docs/version-6.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md new file mode 100644 index 000000000..d5421adcc --- /dev/null +++ b/website/versioned_docs/version-6.x/using-react-redux/connect-dispatching-actions-with-mapDispatchToProps.md @@ -0,0 +1,410 @@ +--- +id: version-6.x-connect-mapdispatch +title: Connect: Dispatching Actions with mapDispatchToProps +hide_title: true +sidebar_label: Connect: Dispatching Actions with mapDispatchToProps +original_id: connect-mapdispatch +--- + +# Connect: Dispatching Actions with `mapDispatchToProps` + +As the second argument passed in to `connect`, `mapDispatchToProps` is used for dispatching actions to the store. + +`dispatch` is a function of the Redux store. You call `store.dispatch` to dispatch an action. +This is the only way to trigger a state change. + +With React Redux, your components never access the store directly - `connect` does it for you. +React Redux gives you two ways to let components dispatch actions: + +- By default, a connected component receives `props.dispatch` and can dispatch actions itself. +- `connect` can accept an argument called `mapDispatchToProps`, which lets you create functions that dispatch when called, and pass those functions as props to your component. + +The `mapDispatchToProps` functions are normally referred to as `mapDispatch` for short, but the actual variable name used can be whatever you want. + +## Approaches for Dispatching + +### Default: `dispatch` as a Prop + +If you don't specify the second argument to `connect()`, your component will receive `dispatch` by default. For example: + +```js +connect()(MyComponent) +// which is equivalent with +connect( + null, + null +)(MyComponent) + +// or +connect(mapStateToProps /** no second argument */)(MyComponent) +``` + +Once you have connected your component in this way, your component receives `props.dispatch`. You may use it to dispatch actions to the store. + +```js +function Counter({ count, dispatch }) { + return ( +
+ + {count} + + +
+ ) +} +``` + +### Providing A `mapDispatchToProps` Parameter + +Providing a `mapDispatchToProps` allows you to specify which actions your component might need to dispatch. It lets you provide action dispatching functions as props. Therefore, instead of calling `props.dispatch(() => increment())`, you may call `props.increment()` directly. There are a few reasons why you might want to do that. + +#### More Declarative + +First, encapsulating the dispatch logic into function makes the implementation more declarative. +Dispatching an action and letting the Redux store handle the data flow is _how to_ implement the behavior, rather than _what_ it does. + +A good example would be dispatching an action when a button is clicked. Connecting the button directly probably doesn't make sense conceptually, and neither does having the button reference `dispatch`. + +```js +// button needs to be aware of "dispatch" + + {count} + + + + ) +} +``` + +(Full code of the Counter example is [in this CodeSandbox](https://codesandbox.io/s/yv6kqo1yw9)) + +### Defining the `mapDispatchToProps` Function with `bindActionCreators` + +Wrapping these functions by hand is tedious, so Redux provides a function to simplify that. + +> `bindActionCreators` turns an object whose values are [action creators](https://redux.js.org/glossary#action-creator), into an object with the same keys, but with every action creator wrapped into a [`dispatch`](https://redux.js.org/api/store#dispatch) call so they may be invoked directly. See [Redux Docs on `bindActionCreators`](http://redux.js.org/docs/api/bindActionCreators.html) + +`bindActionCreators` accepts two parameters: + +1. A **`function`** (an action creator) or an **`object`** (each field an action creator) +2. `dispatch` + +The wrapper functions generated by `bindActionCreators` will automatically forward all of their arguments, so you don't need to do that by hand. + +```js +import { bindActionCreators } from 'redux' + +const increment = () => ({ type: 'INCREMENT' }) +const decrement = () => ({ type: 'DECREMENT' }) +const reset = () => ({ type: 'RESET' }) + +// binding an action creator +// returns (...args) => dispatch(increment(...args)) +const boundIncrement = bindActionCreators(increment, dispatch) + +// binding an object full of action creators +const boundActionCreators = bindActionCreators( + { increment, decrement, reset }, + dispatch +) +// returns +// { +// increment: (...args) => dispatch(increment(...args)), +// decrement: (...args) => dispatch(decrement(...args)), +// reset: (...args) => dispatch(reset(...args)), +// } +``` + +To use `bindActionCreators` in our `mapDispatchToProps` function: + +```js +import { bindActionCreators } from 'redux' +// ... + +function mapDispatchToProps(dispatch) { + return bindActionCreators({ increment, decrement, reset }, dispatch) +} + +// component receives props.increment, props.decrement, props.reset +connect( + null, + mapDispatchToProps +)(Counter) +``` + +### Manually Injecting `dispatch` + +If the `mapDispatchToProps` argument is supplied, the component will no longer receive the default `dispatch`. You may bring it back by adding it manually to the return of your `mapDispatchToProps`, although most of the time you shouldn’t need to do this: + +```js +import { bindActionCreators } from 'redux' +// ... + +function mapDispatchToProps(dispatch) { + return { + dispatch, + ...bindActionCreators({ increment, decrement, reset }, dispatch) + } +} +``` + +## Defining `mapDispatchToProps` As An Object + +You’ve seen that the setup for dispatching Redux actions in a React component follows a very similar process: define an action creator, wrap it in another function that looks like `(…args) => dispatch(actionCreator(…args))`, and pass that wrapper function as a prop to your component. + +Because this is so common, `connect` supports an “object shorthand” form for the `mapDispatchToProps` argument: if you pass an object full of action creators instead of a function, `connect` will automatically call `bindActionCreators` for you internally. + +**We recommend always using the “object shorthand” form of `mapDispatchToProps`, unless you have a specific reason to customize the dispatching behavior.** + +Note that: + +- Each field of the `mapDispatchToProps` object is assumed to be an action creator +- Your component will no longer receive `dispatch` as a prop + +```js +// React Redux does this for you automatically: +dispatch => bindActionCreators(mapDispatchToProps, dispatch) +``` + +Therefore, our `mapDispatchToProps` can simply be: + +```js +const mapDispatchToProps = { + increment, + decrement, + reset +} +``` + +Since the actual name of the variable is up to you, you might want to give it a name like `actionCreators`, or even define the object inline in the call to `connect`: + +```js +import {increment, decrement, reset} from "./counterActions"; + +const actionCreators = { + increment, + decrement, + reset +} + +export default connect(mapState, actionCreators)(Counter); + +// or +export default connect( + mapState, + { increment, decrement, reset } +)(Counter); +``` + +## Common Problems + +### Why is my component not receiving `dispatch`? + +Also known as + +```js +TypeError: this.props.dispatch is not a function +``` + +This is a common error that happens when you try to call `this.props.dispatch` , but `dispatch` is not injected to your component. + +`dispatch` is injected to your component _only_ when: + +**1. You do not provide `mapDispatchToProps`** + +The default `mapDispatchToProps` is simply `dispatch => ({ dispatch })`. If you do not provide `mapDispatchToProps`, `dispatch` will be provided as mentioned above. + +In another words, if you do: + +```js +// component receives `dispatch` +connect(mapStateToProps /** no second argument*/)(Component) +``` + +**2. Your customized `mapDispatchToProps` function return specifically contains `dispatch`** + +You may bring back `dispatch` by providing your customized `mapDispatchToProps` function: + +```js +const mapDispatchToProps = dispatch => { + return { + increment: () => dispatch(increment()), + decrement: () => dispatch(decrement()), + reset: () => dispatch(reset()), + dispatch + } +} +``` + +Or alternatively, with `bindActionCreators`: + +```js +import { bindActionCreators } from 'redux' + +function mapDispatchToProps(dispatch) { + return { + dispatch, + ...bindActionCreators({ increment, decrement, reset }, dispatch) + } +} +``` + +See [this error in action in Redux’s GitHub issue #255](https://github.com/reduxjs/react-redux/issues/255). + +There are discussions regarding whether to provide `dispatch` to your components when you specify `mapDispatchToProps` ( [Dan Abramov’s response to #255](https://github.com/reduxjs/react-redux/issues/255#issuecomment-172089874) ). You may read them for further understanding of the current implementation intention. + +### Can I `mapDispatchToProps` without `mapStateToProps` in Redux? + +Yes. You can skip the first parameter by passing `undefined` or `null`. Your component will not subscribe to the store, and will still receive the dispatch props defined by `mapDispatchToProps`. + +```js +connect( + null, + mapDispatchToProps +)(MyComponent) +``` + +### Can I call `store.dispatch`? + +It's an anti-pattern to interact with the store directly in a React component, whether it's an explicit import of the store or accessing it via context (see the [Redux FAQ entry on store setup](https://redux.js.org/faq/storesetup#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) for more details). Let React Redux’s `connect` handle the access to the store, and use the `dispatch` it passes to the props to dispatch actions. + +## Links and References + +**Tutorials** + +- [You Might Not Need the `mapDispatchToProps` Function](https://daveceddia.com/redux-mapdispatchtoprops-object-form/) + +**Related Docs** + +- [Redux Doc on `bindActionCreators`](https://redux.js.org/api/bindactioncreators) + +**Q&A** + +- [How to get simple dispatch from `this.props` using connect with Redux?](https://stackoverflow.com/questions/34458261/how-to-get-simple-dispatch-from-this-props-using-connect-w-redux) +- [`this.props.dispatch` is `undefined` if using `mapDispatchToProps`](https://github.com/reduxjs/react-redux/issues/255) +- [Do not call `store.dispatch`, call `this.props.dispatch` injected by `connect` instead](https://github.com/reduxjs/redux/issues/916) +- [Can I `mapDispatchToProps` without `mapStateToProps` in Redux?](https://stackoverflow.com/questions/47657365/can-i-mapdispatchtoprops-without-mapstatetoprops-in-redux) +- [Redux Doc FAQ: React Redux](https://redux.js.org/faq/reactredux) diff --git a/website/versioned_docs/version-6.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md b/website/versioned_docs/version-6.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md new file mode 100644 index 000000000..4b798605a --- /dev/null +++ b/website/versioned_docs/version-6.x/using-react-redux/connect-extracting-data-with-mapStateToProps.md @@ -0,0 +1,229 @@ +--- +id: version-6.x-connect-mapstate +title: Connect: Extracting Data with mapStateToProps +hide_title: true +sidebar_label: Connect: Extracting Data with mapStateToProps +original_id: connect-mapstate +--- + +# Connect: Extracting Data with `mapStateToProps` + +As the first argument passed in to `connect`, `mapStateToProps` is used for selecting the part of the data from the store that the connected component needs. It’s frequently referred to as just `mapState` for short. + +- It is called every time the store state changes. +- It receives the entire store state, and should return an object of data this component needs. + +## Defining `mapStateToProps` + +`mapStateToProps` should be defined as a function: + +```js +function mapStateToProps(state, ownProps?) +``` + +It should take a first argument called `state`, optionally a second argument called `ownProps`, and return a plain object containing the data that the connected component needs. + +This function should be passed as the first argument to `connect`, and will be called every time when the Redux store state changes. If you do not wish to subscribe to the store, pass `null` or `undefined` to `connect` in place of `mapStateToProps`. + +**It does not matter if a `mapStateToProps` function is written using the `function` keyword (`function mapState(state) { }` ) or as an arrow function (`const mapState = (state) => { }` )** - it will work the same either way. + +### Arguments + +1. **`state`** +2. **`ownProps` (optional)** + +#### `state` + +The first argument to a `mapStateToProps` function is the entire Redux store state (the same value returned by a call to `store.getState()`). Because of this, the first argument is traditionally just called `state`. (While you can give the argument any name you want, calling it `store` would be incorrect - it's the "state value", not the "store instance".) + +The `mapStateToProps` function should always be written with at least `state` passed in. + +```js +// TodoList.js + +function mapStateToProps(state) { + const { todos } = state + return { todoList: todos.allIds } +} + +export default connect(mapStateToProps)(TodoList) +``` + +#### `ownProps` (optional) + +You may define the function with a second argument, `ownProps`, if your component needs the data from its own props to retrieve data from the store. This argument will contain all of the props given to the wrapper component that was generated by `connect`. + +```js +// Todo.js + +function mapStateToProps(state, ownProps) { + const { visibilityFilter } = state + const { id } = ownProps + const todo = getTodoById(state, id) + + // component receives additionally: + return { todo, visibilityFilter } +} + +// Later, in your application, a parent component renders: +; +// and your component receives props.id, props.todo, and props.visibilityFilter +``` + +You do not need to include values from `ownProps` in the object returned from `mapStateToProps`. `connect` will automatically merge those different prop sources into a final set of props. + +### Return + +Your `mapStateToProps` function should return a plain object that contains the data the component needs: + +- Each field in the object will become a prop for your actual component +- The values in the fields will be used to determine if your component needs to re-render + +For example: + +```js +function mapStateToProps(state) { + return { + a: 42, + todos: state.todos, + filter: state.visibilityFilter + } +} + +// component will receive: props.a, props.todos, and props.filter +``` + +> Note: In advanced scenarios where you need more control over the rendering performance, `mapStateToProps` can also return a function. In this case, that function will be used as the final `mapStateToProps` for a particular component instance. This allows you to do per-instance memoization. See the [Advanced Usage]() section of the docs for more details, as well as [PR #279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds. Most apps never need this. + +## Usage Guidelines + +### Let `mapStateToProps` Reshape the Data from the Store + +`mapStateToProps` functions can, and should, do a lot more than just `return state.someSlice`. **They have the responsibility of "re-shaping" store data as needed for that component.** This may include returning a value as a specific prop name, combining pieces of data from different parts of the state tree, and transforming the store data in different ways. + +### Use Selector Functions to Extract and Transform Data + +We highly encourage the use of "selector" functions to help encapsulate the process of extracting values from specific locations in the state tree. Memoized selector functions also play a key role in improving application performance (see the following sections in this page and the [Advanced Usage: Performance]() page for more details on why and how to use selectors.) + +### `mapStateToProps` Functions Should Be Fast + +Whenever the store changes, all of the `mapStateToProps` functions of all of the connected components will run. Because of this, your `mapStateToProps` functions should run as fast as possible. This also means that a slow `mapStateToProps` function can be a potential bottleneck for your application. + +As part of the "re-shaping data" idea, `mapStateToProps` functions frequently need to transform data in various ways (such as filtering an array, mapping an array of IDs to their corresponding objects, or extracting plain JS values from Immutable.js objects). These transformations can often be expensive, both in terms of cost to execute the transformation, and whether the component re-renders as a result. If performance is a concern, ensure that these transformations are only run if the input values have changed. + +### `mapStateToProps` Functions Should Be Pure and Synchronous + +Much like a Redux reducer, a `mapStateToProps` function should always be 100% pure and synchronous. It should simply take `state` (and `ownProps`) as arguments, and return the data the component needs as props. It should _not_ be used to trigger asynchronous behavior like AJAX calls for data fetching, and the functions should not be declared as `async`. + +## `mapStateToProps` and Performance + +### Return Values Determine If Your Component Re-Renders + +React Redux internally implements the `shouldComponentUpdate` method such that the wrapper component re-renders precisely when the data your component needs has changed. By default, React Redux decides whether the contents of the object returned from `mapStateToProps` are different using `===` comparison (a "shallow equality" check) on each fields of the returned object. If any of the fields have changed, then your component will be re-rendered so it can receive the updated values as props. Note that returning a mutated object of the same reference is a common mistake that can result in your component not re-rendering when expected. + +To summarize the behavior of the component wrapped by `connect` with `mapStateToProps` to extract data from the store: + +| | `(state) => stateProps` | `(state, ownProps) => stateProps` | +| ---------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------- | +| `mapStateToProps` runs when: | store `state` changes | store `state` changes
or
any field of `ownProps` is different | +| component re-renders when: | any field of `stateProps` is different | any field of `stateProps` is different
or
any field of `ownProps` is different | + +### Only Return New Object References If Needed + +React Redux does shallow comparisons to see if the `mapStateToProps` results have changed. It’s easy to accidentally return new object or array references every time, which would cause your component to re-render even if the data is actually the same. + +Many common operations result in new object or array references being created: + +- Creating new arrays with `someArray.map()` or `someArray.filter()` +- Merging arrays with `array.concat` +- Selecting portion of an array with `array.slice` +- Copying values with `Object.assign` +- Copying values with the spread operator `{ ...oldState, ...newData }` + +Put these operations in [memoized selector functions]() to ensure that they only run if the input values have changed. This will also ensure that if the input values _haven't_ changed, `mapStateToProps` will still return the same result values as before, and `connect` can skip re-rendering. + +### Only Perform Expensive Operations When Data Changes + +Transforming data can often be expensive (_and_ usually results in new object references being created). In order for your `mapStateToProps` function to be as fast as possible, you should only re-run these complex transformations when the relevant data has changed. + +There are a few ways to approach this: + +- Some transformations could be calculated in an action creator or reducer, and the transformed data could be kept in the store +- Transformations can also be done in a component's `render()` method +- If the transformation does need to be done in a `mapStateToProps` function, then we recommend using [memoized selector functions]() to ensure the transformation is only run when the input values have changed. + +#### Immutable.js Performance Concerns + +Immutable.js author Lee Byron on Twitter [explicitly advises avoiding `toJS` when performance is a concern](https://twitter.com/leeb/status/746733697093668864?lang=en): + +> Perf tip for #immutablejs: avoid .toJS() .toObject() and .toArray() all slow full-copy operations which render structural sharing useless. + +There's several other performance concerns to take into consideration with Immutable.js - see the list of links at the end of this page for more information. + +## Behavior and Gotchas + +### `mapStateToProps` Will Not Run if the Store State is the Same + +The wrapper component generated by `connect` subscribes to the Redux store. Every time an action is dispatched, it calls `store.getState()` and checks to see if `lastState === currentState`. If the two state values are identical by reference, then it will _not_ re-run your `mapStateToProps` function, because it assumes that the rest of the store state hasn't changed either. + +The Redux `combineReducers` utility function tries to optimize for this. If none of the slice reducers returned a new value, then `combineReducers` returns the old state object instead of a new one. This means that mutation in a reducer can lead to the root state object not being updated, and thus the UI won't re-render. + +### The Number of Declared Arguments Affects Behavior + +With just `(state)`, the function runs whenever the root store state object is different. With `(state, ownProps)`, it runs any time the store state is different and ALSO whenever the wrapper props have changed. + +This means that **you should not add the `ownProps` argument unless you actually need to use it**, or your `mapStateToProps` function will run more often than it needs to. + +There are some edge cases around this behavior. **The number of mandatory arguments determines whether `mapStateToProps` will receive `ownProps`**. + +If the formal definition of the function contains one mandatory parameter, `mapStateToProps` will _not_ receive `ownProps`: + +```js +function mapStateToProps(state) { + console.log(state) // state + console.log(arguments[1]) // undefined +} +const mapStateToProps = (state, ownProps = {}) => { + console.log(state) // state + console.log(ownProps) // undefined +} +``` + +It _will_ receive `ownProps` when the formal definition of the function contains zero or two mandatory parameters: + +```js +function mapStateToProps(state, ownProps) { + console.log(state) // state + console.log(ownProps) // ownProps +} + +function mapStateToProps() { + console.log(arguments[0]) // state + console.log(arguments[1]) // ownProps +} + +function mapStateToProps(...args) { + console.log(args[0]) // state + console.log(args[1]) // ownProps +} +``` + +## Links and References + +**Tutorials** + +- [Practical Redux Series, Part 6: Connected Lists, Forms, and Performance](https://blog.isquaredsoftware.com/2017/01/practical-redux-part-6-connected-lists-forms-and-performance/) +- [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) + +**Performance** + +- [Lee Byron's Tweet Suggesting to avoid `toJS`, `toArray` and `toObject` for Performance](https://twitter.com/leeb/status/746733697093668864) +- [Improving React and Redux performance with Reselect](https://blog.rangle.io/react-and-redux-performance-with-reselect/) +- [Immutable data performance links](https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data) + +**Q&A** + +- [Why Is My Component Re-Rendering Too Often?](https://redux.js.org/faq/reactredux#why-is-my-component-re-rendering-too-often) +- [Why isn't my component re-rendering, or my mapStateToProps running](https://redux.js.org/faq/reactredux#why-isnt-my-component-re-rendering-or-my-mapstatetoprops-running) +- [How can I speed up my mapStateToProps?](https://redux.js.org/faq/reactredux#why-is-my-component-re-rendering-too-often) +- [Should I only connect my top component, or can I connect multiple components in my tree?](https://redux.js.org/faq/reactredux#why-is-my-component-re-rendering-too-often) diff --git a/website/versioned_sidebars/version-6.x-sidebars.json b/website/versioned_sidebars/version-6.x-sidebars.json new file mode 100644 index 000000000..3e43837af --- /dev/null +++ b/website/versioned_sidebars/version-6.x-sidebars.json @@ -0,0 +1,22 @@ +{ + "version-6.x-docs": { + "Introduction": [ + "version-6.x-introduction/quick-start", + "version-6.x-introduction/basic-tutorial", + "version-6.x-introduction/why-use-react-redux" + ], + "Using React Redux": [ + "version-6.x-using-react-redux/connect-mapstate", + "version-6.x-using-react-redux/connect-mapdispatch", + "version-6.x-using-react-redux/accessing-store" + ], + "API Reference": [ + "version-6.x-api/connect", + "version-6.x-api/provider", + "version-6.x-api/connect-advanced" + ], + "Guides": [ + "version-6.x-troubleshooting" + ] + } +} diff --git a/website/versions.json b/website/versions.json index b2e70a688..3f6328c12 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,3 +1,4 @@ [ + "6.x", "5.x" ] From 8efcb26fab6bc71f2733fd9b2f7572528bab6ea1 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Sun, 7 Apr 2019 13:12:56 +0800 Subject: [PATCH 5/5] Display v7.x as pre-release version --- website/pages/en/versions.js | 19 ++++++++++++++----- website/siteConfig.js | 9 ++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/website/pages/en/versions.js b/website/pages/en/versions.js index b90ef4e97..d090c2ea3 100644 --- a/website/pages/en/versions.js +++ b/website/pages/en/versions.js @@ -16,12 +16,18 @@ const siteConfig = require(`${CWD}/siteConfig.js`); const versions = require(`${CWD}/versions.json`); + const versionToReleaseTags = { + '5.x': '5.0.0', + '6.x': '6.0.0', + '7.x': '7.0.0-beta.0' + } + function Versions() { const latestVersion = versions[0]; const repoUrl = `https://github.com/${siteConfig.organizationName}/${ siteConfig.projectName }`; - const releaseTagUrl = version => `${repoUrl}/releases/tag/v${version}` + const releaseTagUrl = version => versionToReleaseTags.hasOwnProperty(version) ? `${repoUrl}/releases/tag/v${versionToReleaseTags[version]}` : `${repoUrl}/releases/tag/v${version}` return (
@@ -48,8 +54,9 @@ This is the version that is configured automatically when you first install this project.

- {/* uncomment here if we have pre-release notes -

Pre-release versions

+ { + !!siteConfig.nextVersion && ( +

Pre-release versions

@@ -62,14 +69,16 @@ -
*/} + + ) + }

Past Versions

{versions.map( version => version !== latestVersion && ( - +
{version} Documentation diff --git a/website/siteConfig.js b/website/siteConfig.js index 4b2ff280e..5e134978f 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -98,7 +98,14 @@ const siteConfig = { // template. For example, if you need your repo's URL... repoUrl: "https://github.com/reduxjs/react-redux", - // nextVersion: "6.0.0", + /** + * Note: + * This will generate a link on the versioned docs page for "pre-release versions" + * Once next version is released, run "yarn run version 7.x", and docusaurus will add 7.x to stable version + * After that, 7.x will no longer appear in "pre-release" versions and we should remove this line + * More info: https://docusaurus.io/docs/en/versioning + */ + nextVersion: "7.x", gaTrackingId : "UA-130598673-2", };