和 Flux 類似,Redux 也是需要注冊(cè)一個(gè)回調(diào)函數(shù) store.subscribe(listener)
來獲取
State 的更新,然后我們要在 listener
里面調(diào)用 setState()
來更新 React
組件。
Redux 官方提供了 react-redux 來簡化 React 和 Redux 之間的綁定,不再需要像 Flux 那樣手動(dòng)注冊(cè)/解綁回調(diào)函數(shù)。
接下來看一下是怎么做到的,react-redux 只有兩個(gè) API
<Provider>
作為一個(gè)容器組件,用來接受 Store,并且讓 Store
對(duì)子組件可用,用法如下:
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import App from './app';
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
這時(shí)候 <Provider>
里面的子組件 <App />
才可以使用 connect
方法關(guān)聯(lián)
store。
<Provider>
的實(shí)現(xiàn)很簡單,他利用了 React 一個(gè)(暫時(shí))隱藏的特性 Contexts
,Context
用來傳遞一些父容器的屬性對(duì)所有子孫組件可見,在某些場(chǎng)景下面避免了用 props
傳遞多層組件的繁瑣,要想更詳細(xì)了解 Contexts
可以參考這篇文章。
connect()
這個(gè)方法略微復(fù)雜一點(diǎn),主要是因?yàn)樗挠梅ǚ浅l`活:connect([mapStateToProps], mapDispatchToProps], [mergeProps], [options])
,它最多接受4個(gè)參數(shù),都是可選的,并且這個(gè)方法調(diào)用會(huì)返回另一個(gè)函數(shù),這個(gè)返回的函數(shù)來接受一個(gè)組件類作為參數(shù),最后才返回一個(gè)和
Redux store 關(guān)聯(lián)起來的新組件,類似這樣:
class App extends Component { ... }
export default connect()(App);
這樣就可以在 App
這個(gè)組件里面通過 props
拿到 Store 的 dispatch
方法,但是注意現(xiàn)在的 App
沒有監(jiān)聽 Store 的狀態(tài)更改,如果要監(jiān)聽 Store
的狀態(tài)更改,必須要指定 mapStateToProps
參數(shù)。
先來看它的參數(shù):
[mapStateToProps(state, [ownProps]): stateProps]
:
第一個(gè)可選參數(shù)是一個(gè)函數(shù),只有指定了這個(gè)參數(shù),這個(gè)關(guān)聯(lián)(connected)組件才會(huì)監(jiān)聽
Redux Store 的更新,每次更新都會(huì)調(diào)用 mapStateToProps
這個(gè)函數(shù),返回一個(gè)字面量對(duì)象將會(huì)合并到組件的 props
屬性。
ownProps
是可選的第二個(gè)參數(shù),它是傳遞給組件的 props
,當(dāng)組件獲取到新的
props
時(shí),ownProps
都會(huì)拿到這個(gè)值并且執(zhí)行 mapStateToProps
這個(gè)函數(shù)。[mapDispatchProps(dispatch, [ownProps]): dispatchProps]
:
這個(gè)函數(shù)用來指定如何傳遞 dispatch
給組件,在這個(gè)函數(shù)里面直接 dispatch
action creator,返回一個(gè)字面量對(duì)象將會(huì)合并到組件的 props
屬性,這樣關(guān)聯(lián)組件可以直接通過 props
調(diào)用到 action
,
Redux 提供了一個(gè) bindActionCreators()
輔助函數(shù)來簡化這種寫法。
如果省略這個(gè)參數(shù),默認(rèn)直接把 dispatch
作為 props
傳入。ownProps
作用同上。剩下的兩個(gè)參數(shù)比較少用到,更詳細(xì)的說明參看官方文檔,其中提供了很多簡單清晰的用法示例來說明這些參數(shù)。
Redux 創(chuàng)建 Store,Action,Reducer 這部分就省略了,這里只看 react-redux 的部分。
import React, { Component } from 'react';
import someActionCreator from './actions/someAction';
import * as actionCreators from './actions/otherAction';
function mapStateToProps(state) {
return {
propName: state.propName
};
}
function mapDispatchProps(dispatch) {
return {
someAction: (arg) => dispatch(someActionCreator(arg)),
otherActions: bindActionCreators(actionCreators, dispatch)
};
}
class App extends Component {
render() {
// `mapStateToProps` 和 `mapDispatchProps` 返回的字段都是 `props`
const { propName, someAction, otherActions } = this.props;
return (
<div onClick={someAction.bind(this, 'arg')}>
{propName}
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchProps)(App);
如前所述,這個(gè) connected 的組件必須放到 <Provider>
的容器里面,當(dāng) State
更改的時(shí)候就會(huì)自動(dòng)調(diào)用 mapStateToProps
和 mapDispatchProps
從而更新組件的 props
。
組件內(nèi)部也可以通過 props
調(diào)用到 action,如果沒有省略了
mapDispatchProps
,組件要觸發(fā) action 就必須手動(dòng)
dispatch,類似這樣:this.props.dispatch(someActionCreator('arg'))
。