## API
### `<Provider store>`
`<Provider store>` 使組件層級中的 `connect()` 方法都能夠獲得 Redux store。正常情況下,你的根組件應該嵌套在 `<Provider>` 中才能使用 `connect()` 方法。
如果你**真的**不想把根組件嵌套在 `<Provider>` 中,你可以把 `store` 作為 props 傳遞到每一個被 `connect()` 包裝的組件,但是我們只推薦您在單元測試中對 `store` 進行偽造 (stub) 或者在非完全基于 React 的代碼中才這樣做。正常情況下,你應該使用 `<Provider>`。
#### 屬性
- `store` (_[Redux Store](http://cn.redux.js.org/docs/api/Store.html)_): 應用程序中唯一的 Redux store 對象
- `children` (_ReactElement_) 組件層級的根組件。
#### 例子
##### Vanilla React
```js
ReactDOM.render(
<Provider store={store}>
<MyRootComponent />
</Provider>,
rootEl
)
```
##### React Router
```js
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App}>
<Route path="foo" component={Foo} />
<Route path="bar" component={Bar} />
</Route>
</Router>
</Provider>,
document.getElementById('root')
)
```
### `connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])`
連接 React 組件與 Redux store。
連接操作不會改變原來的組件類。
反而**返回**一個新的已與 Redux store 連接的組件類。
#### 參數
- [`mapStateToProps(state, [ownProps]): stateProps`] \(_Function_): 如果定義該參數,組件將會監聽 Redux store 的變化。任何時候,只要 Redux store 發生改變,`mapStateToProps` 函數就會被調用。該回調函數必須返回一個純對象,這個對象會與組件的 props 合并。如果你省略了這個參數,你的組件將不會監聽 Redux store。如果指定了該回調函數中的第二個參數 `ownProps`,則該參數的值為傳遞到組件的 props,而且只要組件接收到新的 props,`mapStateToProps` 也會被調用(例如,當 props 接收到來自父組件一個小小的改動,那么你所使用的 ownProps 參數,mapStateToProps 都會被重新計算)。
> 注意:在高級章節中,你需要更好地去控制渲染的性能,所用到的 `mapStateToProps()` 會返回一個函數。在這種情況下,**那個**函數將被作為 `mapStateToProps()` 在獨有的組件實例中調用。這樣就允許你在每一個實例中去記錄。你可以參考 [#279](https://github.com/reactjs/react-redux/pull/279) 去測試和了解其中的詳細內容。但在絕大多數的應用中不會用到。
- [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(_Object_ or _Function_): 如果傳遞的是一個對象,那么每個定義在該對象的函數都將被當作 Redux action creator,對象所定義的方法名將作為屬性名;每個方法將返回一個新的函數,函數中`dispatch`方法會將 action creator 的返回值作為參數執行。這些屬性會被合并到組件的 props 中。
如果傳遞的是一個函數,該函數將接收一個 `dispatch` 函數,然后由你來決定如何返回一個對象,這個對象通過 `dispatch` 函數與 action creator 以某種方式綁定在一起(提示:你也許會用到 Redux 的輔助函數 [`bindActionCreators()`](http://cn.redux.js.org/docs/api/bindActionCreators.html)。如果你省略這個 `mapDispatchToProps` 參數,默認情況下,`dispatch` 會注入到你的組件 props 中。如果指定了該回調函數中第二個參數 `ownProps`,該參數的值為傳遞到組件的 props,而且只要組件接收到新 props,`mapDispatchToProps` 也會被調用。
> 注意:在高級章節中,你需要更好地去控制渲染的性能,所用到的 `mapStateToProps()` 會返回一個函數。但在這個例子中,**這個**函數將被 `mapStateToProps()` 在獨有的組件實例中調用。這樣就允許你在每一個實例中去記錄。你可以參考 [#279](https://github.com/reactjs/react-redux/pull/279) 去測試和了解其中的詳細內容。但在絕大多數的應用中不會用到。
> `mapStateToProps` 函數的第一個參數是整個 Redux store 的 state,它返回一個要作為 props 傳遞的對象。它通常被稱作 **selector** (選擇器)。 可以使用[reselect](https://github.com/reactjs/reselect)去有效地組合選擇器和[計算衍生數據](http://cn.redux.js.org/docs/recipes/ComputingDerivedData.html).
- [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(_Function_): 如果指定了這個參數,`mapStateToProps()` 與 `mapDispatchToProps()` 的執行結果和組件自身的 `props` 將傳入到這個回調函數中。該回調函數返回的對象將作為 props 傳遞到被包裝的組件中。你也許可以用這個回調函數,根據組件的 props 來篩選部分的 state 數據,或者把 props 中的某個特定變量與 action creator 綁定在一起。如果你省略這個參數,默認情況下返回 `Object.assign({}, ownProps, stateProps, dispatchProps)` 的結果。
- [`options`] _(Object)_ 如果指定這個參數,可以定制 connector 的行為。
- [`pure = true`] _(Boolean)_: 如果為 true,connector 將執行 `shouldComponentUpdate` 并且淺對比 `mergeProps` 的結果,避免不必要的更新,前提是當前組件是一個“純”組件,它不依賴于任何的輸入或 state 而只依賴于 props 和 Redux store 的 state。_默認值為 `true`。_
- [`withRef = false`] _(Boolean)_: 如果為 true,connector 會保存一個對被被包含的組件實例的引用,該引用通過 `getWrappedInstance()` 方法獲得。_默認值為 `false`。_
> 注意:如果定義一個包含強制性參數函數(這個函數的長度為 1)時,`ownProps` **不會傳到** `mapStateToProps` 和 `mapDispatchToProps` 中。舉個例子,如下這樣定義一個函數時將不會接收到 `ownProps` 作為第二個參數。
```javascript
function mapStateToProps(state) {
console.log(state) // state
console.log(arguments[1]) // undefined
}
```
```javascript
const mapStateToProps = (state, ownProps = {}) => {
console.log(state) // state
console.log(ownProps) // undefined
}
```
當函數沒有強制性的參數或兩個參數時**將接收到** `ownProps`。
```javascript
const mapStateToProps = (state, ownProps) => {
console.log(state) // state
console.log(ownProps) // ownProps
}
```
```javascript
function mapStateToProps() {
console.log(arguments[0]) // state
console.log(arguments[1]) // ownProps
}
```
```javascript
const mapStateToProps = (...args) => {
console.log(args[0]) // state
console.log(args[1]) // ownProps
}
```
#### 返回值
根據配置信息,返回一個注入了 state 和 action creator 的 React 組件。
##### 靜態屬性
- `WrappedComponent` _(Component)_: 傳遞到 `connect()` 函數的原始組件類。
##### 靜態方法
組件原來的靜態方法都被提升到被包裝的 React 組件。
##### 實例方法
###### `getWrappedInstance(): ReactComponent`
僅當 `connect()` 函數的第四個參數 `options` 設置了 `{ withRef: true }` 才返回被包裝的組件實例。
#### 備注
- 函數將被調用兩次。第一次是設置參數,第二次是組件與 Redux store 連接:`connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)`。
- connect 函數不會修改傳入的 React 組件,返回的是一個新的已與 Redux store 連接的組件,而且你應該使用這個新組件。
- `mapStateToProps` 函數接收整個 Redux store 的 state 作為 props,然后返回一個傳入到組件 props 的對象。該函數被稱之為 **selector**。參考使用 [reselect](https://github.com/reactjs/reselect) 高效地組合多個 **selector** ,并對 [收集到的數據進行處理](http://cn.redux.js.org/docs/recipes/ComputingDerivedData.html)。
#### Examples 例子
##### 只注入 `dispatch`,不監聽 store
```js
export default connect()(TodoApp)
```
##### 注入全部沒有訂閱 store 的 action creators (`addTodo`, `completeTodo`, ...)
```js
import * as actionCreators from './actionCreators'
export default connect(
null,
actionCreators
)(TodoApp)
```
##### 注入 `dispatch` 和全局 state
> 不要這樣做!這會導致每次 action 都觸發整個 `TodoApp` 重新渲染,你做的所有性能優化都將付之東流。
>
> 最好在多個組件上使用 `connect()`,每個組件只監聽它所關聯的部分 state。
```js
export default connect(state => state)(TodoApp)
```
##### 注入 `dispatch` 和 `todos`
```js
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps)(TodoApp)
```
##### 注入 `todos` 和所有 action creator
```js
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(
mapStateToProps,
actionCreators
)(TodoApp)
```
##### 注入 `todos` 并把所有 action creator (`addTodo`, `completeTodo`, ...) 作為 `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)
```
##### 注入 `todos` 和指定的 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)
```
##### 簡寫語法注入 `todos` 和特定的 action 創建函數(`addTodo` and `deleteTodo`)
```js
import { addTodo, deleteTodo } from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
const mapDispatchToProps = {
addTodo,
deleteTodo
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoApp)
```
##### 注入 `todos` 并把 todoActionCreators 作為 `todoActions` 屬性、counterActionCreators 作為 `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)
```
##### 注入 `todos` 并把 todoActionCreators 與 counterActionCreators 一同作為 `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)
```
##### 注入 `todos` 并把所有的 todoActionCreators 和 counterActionCreators 作為 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)
```
##### 根據組件的 props 注入特定用戶的 `todos`
```js
import * as actionCreators from './actionCreators'
function mapStateToProps(state, ownProps) {
return { todos: state.todos[ownProps.userId] }
}
export default connect(mapStateToProps)(TodoApp)
```
##### 根據組件的 props 注入特定用戶的 `todos` 并把 `props.userId` 傳入到 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)函數
工廠函數可用于性能優化。
```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)
```
<a id="connectAdvanced"></a>
### `connectAdvanced(selectorFactory, [connectOptions])`
它是一個將 React 組件連接到 Redux store 的函數。這個函數是 `connect()` 的基礎,但是對于如何把`state`, `props`, 和 `dispatch` 組合到最后的 props 中,則不那么自以為是。它不對默認值或結果的記錄做任何假設,而是將這些責任留給調用者。
它不修改傳遞給它的組件類;相反,它*返回*一個新的、已連接的組件類,供您使用。
<a id="connectAdvanced-arguments"></a>
#### 參數
- `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(_Function_):初始化選擇器函數 (在每個實例的構造函數中)。該選擇器函數是在 connector 組件需要重新計算一個新的 props 時調用,作為 store 的 state 改變或者接收到一個新的 props 的結果。`selector` 的結果應該是一個普通對象,作為被包裹的組件的 props 傳遞。如果連續調用 `selector` 都返回與上一次調用相同的對象(`===`),則不會重新渲染該組件。`selector` 的責任是在適當的時候返回以前的對象。
- [`connectOptions`] _(Object)_ 如果指定,則進一步自定義連接器(connector)的行為。
- [`getDisplayName`] _(Function)_: 計算連接器組件相對于被包裹的組件的 DisplayName 屬性。 通常被包裹函數覆蓋。 默認值: `name => 'ConnectAdvanced('+name+')'`
- [`methodName`] _(String)_:顯示在錯誤消息中。 通常被包裹函數覆蓋。 默認值: `'connectAdvanced'`
- [`renderCountProp`] _(String)_: 如果被定義, 名為此值的屬性將添加到傳遞給被包裹組件的 props 中。它的值將是組件被渲染的次數,這對于跟蹤不必要的重新渲染非常有用。默認值: `undefined`
- [`shouldHandleStateChanges`] _(Boolean)_: 控制連接器(connector)組件是否訂閱 redux store 的 state 更改。 如果設置為 false,則只會在`componentWillReceiveProps`中重新渲染。 默認值: `true`
- [`storeKey`] _(String)_: 可以獲取 store 的 props/context key。 當你不明智地使用了多個 store 的時候,你才可能需要這個。默認值: `'store'`
- [`withRef`] _(Boolean)_: 如果為 true,則將一個引用存儲到被包裹的組件實例中,并通過 `getWrappedInstance()` 方法使其可用。 默認值: `false`
- 此外,通過 `connectOptions` 傳遞的任何額外選項都將傳遞給 `factorOptions` 參數中的 `selectorFactory`。
<a id="connectAdvanced-returns"></a>
#### 返回值
一個高階 React 組件類,它從 store 的 state 生成 props 并將它們傳遞給被包裹的組件。高階組件是接受組件參數并返回新組件的函數.
##### 靜態屬性
- `WrappedComponent` _(Component)_: 原始組件類傳遞給 `connectAdvanced(...)(Component)`.
##### 靜態函數
組件的所有原始靜態方法都被掛起。
##### 實例方法
###### `getWrappedInstance(): ReactComponent`
返回被包裹組件的實例。只有當你傳遞 `{ withRef: true }` 作為`options` 的參數才可用。
#### 注意
- 因為 `connectAdvanced` 返回一個高階組件,所以需要調用它兩次。 第一次使用上面描述的參數,第二次使用組件: `connectAdvanced(selectorFactory)(MyComponent)`.
- `connectAdvanced` 不修改傳遞的 React 組件。它返回一個新的連接組件,您應該使用它。
<a id="connectAdvanced-examples"></a>
#### 例子
##### 根據 props 將特定用戶的 `todos` 注入,并將 `pros.userid` 注入到操作中
```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)
```
<a id="createProvider"></a>
### `createProvider([storeKey])`
創建一個新的`<Provider>`,它將在上下文的傳遞 key 上設置 Redux Store。 當你不明智地使用了多個 store 的時候,你才可能需要這個。您還需要將相同的 `storeKey` 傳遞給[`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)的 `options` 參數。
<a id="createProvider-arguments"></a>
#### 參數
- [`storeKey`](*String*): The key of the context on which to set the store.要在其上設置 store 的上下文的 key。 默認值: `'store'`
#### 例子
在創建多個 store 之前,請瀏覽以下常見問題: [我是否可以或應該創建多個 store?](https://cn.redux.js.org/docs/faq/StoreSetup.html#store-setup-multiple-stores)
```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 }
```
現在,您可以 import 上面的 `Provider`和 `connect` 并使用它們。
- 自述
- 介紹
- 動機
- 核心概念
- 三大原則
- 先前技術
- 學習資源
- 生態系統
- 示例
- 基礎
- Action
- Reducer
- Store
- 數據流
- 搭配 React
- 示例:Todo List
- 高級
- 異步 Action
- 異步數據流
- Middleware
- 搭配 React Router
- 示例:Reddit API
- 下一步
- 技巧
- 配置 Store
- 遷移到 Redux
- 使用對象展開運算符
- 減少樣板代碼
- 服務端渲染
- 編寫測試
- 計算衍生數據
- 實現撤銷重做
- 子應用隔離
- 組織 Reducer
- Reducer 基礎概念
- Reducer 基礎結構
- Reducer 邏輯拆分
- Reducer 重構示例
- combineReducers 用法
- combineReducers 進階
- State 范式化
- 管理范式化數據
- Reducer 邏輯復用
- 不可變更新模式
- 初始化 State
- 結合 Immutable.JS 使用 Redux
- 常見問題
- 綜合
- Reducer
- 組織 State
- 創建 Store
- Action
- 不可變數據
- 代碼結構
- 性能
- 設計哲學
- React Redux
- 其它
- 排錯
- 詞匯表
- API 文檔
- createStore
- Store
- combineReducers
- applyMiddleware
- bindActionCreators
- compose
- react-redux 文檔
- API
- 排錯