說明:閱讀本篇文章需要對Redux有一定的瞭解,對Redux不瞭解的同學可先看看這篇文章Redux技術架構簡介(一)
1. React中引入react-redux
為了讓Redux和React更好的配合,Facebook專門開發了一個npm包–react-redux,可以這樣引入你的專案: npm install --save react-redux
當然不引用也完全可以(Redux包是必須要引用的),只不過會增加一些開發量,還會帶來一些額外的效能開銷。
2. 展示元件與容器元件
Redux的React繫結庫的基本開發思想是展示元件與容器元件相分離。展示元件只負責頁面呈現,不處理資料,不維護狀態;容器元件負責頁面的執行邏輯,獲取展示元件中的訊息,處理內部資料,更新狀態等。
3. 展示元件的實現
React引入redux後,應用中只有單一的state樹,react的每個元件都可以拋棄state的相關邏輯,改為從props獲取,包括要執行的一些使用者事件行為。
引入redux後的react元件變為:
class MainContent extends React.Component{
constructor(props){
super(props);
this.sortResult = this.sortResult.bind(this);
this.showSlider = this.showSlider.bind(this);
}
sortResult(data){
this.props.setPhoto(data);
}
showSlider(index){
this.props.showSlider(index);
}
componentDidMount () {
this.props.fetchPosts();
}
render(){
let {isFetching, isValidate} = this.props;
let sliderNode = null;
if(this.props.photo.length){
sliderNode = <PhotoSliderContainer data={this.props.photo} />;
}
return (
<div className="mainContent">
<Header title="photo" />
<SortContainer data={this.props.photo} sortResult={this.sortResult}/>
<PhotoItemsContainer data={this.props.photo} showSlider = {this.showSlider}/>
{sliderNode}
</div>
);
}
};
可以看到,MainContent元件除了展示外,幾乎沒有任何的邏輯處理(subscribe和dispatch的邏輯都放到了容器元件),所有的資料都是通過this.props從父元件中獲取。
4. 容器元件的實現
容器元件實現了將展示元件和redux關聯在一起。技術上講,容器元件就是使用 store.subscribe() 從 Redux state 樹中讀取部分資料,並通過 props 來把這些資料提供給要渲染的元件。建議每個展示元件對應一個容器元件,這樣可以很清晰的找到對映關係。
mapStateToProps函式
從名字上可以看出,這個函式實現了從state(reducer中定義的)到展示元件props 的對映。示例程式碼如下:
const mapStateToProps = (state, ownProps) => {
return {
photo : state.photomainReducer.photoData,
video : state.photomainReducer.videoData,
isFetching : state.photomainReducer.isFetching,
isValidate : state.photomainReducer.isValidate
}
}
傳入的state是應用中唯一的狀態樹,我們從相應元件的reducer中讀取state,分別對映到一個自定義屬性中,這樣就可以在展示元件中直接呼叫對應屬性(props)了。
mapStateToProps會訂閱 Store,每當state更新的時候,就會自動執行,重新計算 UI 元件的引數,從而觸發 UI 元件的重新渲染。
mapDispatchToProps函式
同樣我們也可以猜到,這個函式的作用是將期望執行的dispatch方法的返回值對映到展示元件的props上。示例程式碼如下:
const mapDispatchToProps = (dispatch, ownProps) => {
return {
slider:(data) => dispatch(photomainAction.showSlider(data))
}
}
比如我們想dispatch一個showSlider的action,通過這個方法對映之後,就可以直接這樣寫:
this.props.slider(data)
即mapDispatchToProps封裝了dispatch方法。此外,還可以通過redux提供的bindActionCreators函式進一步封裝,上面的程式碼可以改寫如下:
const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({
slider:photomainAction.showSlider
},dispatch);
}
如果import時的action名和你想定義的屬性名一樣,甚至還可以簡化:
const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({slider},dispatch);
}
connect函式
上面2個方法實現了state和action到props的對映,我們還需要把這2個函式連線在一起,並且要關聯到一個具體的展示元件,這樣就可以在展示元件中使用這種對映關係了。示例程式碼如下:
const PhotomainContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Photomain);
其中,Photomain是一個展示元件。
每一個容器元件都包含一個對應的展示元件,我們可以把這些容器元件當做一個普通的react元件進行組合,整合的最後一步就是如何把store傳入到每個元件中。
5. 傳入Store
Store儲存了整個應用的單一狀態樹,所有容器元件都需要從store中讀取,我們可以store作為屬性傳遞給每個元件,子元件通過props獲取,但是如果巢狀過深,寫起來會很麻煩。還好,react-redux提供一個叫provider的元件,他可以讓所有元件都可以訪問到store(他的實現原理實際上是利用了react的context功能),而不必顯示的一層層傳遞了。
ReactDOM.render(
<Provider store={store}>
<PhotomainContainer></PhotomainContainer>
</Provider>,
$(".main-wrap")[0]
);
有一點要注意,provider內的元件只能有一個,所以需要將所有元件先封裝成一個元件再用provider包裹起來。
6. 總結
Redux的引入使React徹底脫離了對資料狀態的管理,可以讓React更專注於View的展現,實際上這也是react善於做的事情。單獨看react,我們甚至感覺不到redux的存在,使邏輯層和檢視層更加清晰(redux負責邏輯,react負責檢視),當然一部分原因要歸功於react-redux包做了很好的封裝。
以上就是React與Redux整合的簡單實現。