React與Redux整合技術簡介

brantni發表於2018-05-17

說明:閱讀本篇文章需要對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整合的簡單實現。

參考

Redux 中文文件
Redux 入門教程-阮一峰

相關文章