1. 程式人生 > >徹底弄懂React-Redux元件通訊

徹底弄懂React-Redux元件通訊

為了方便使用,Redux的作者封裝了一個React專用的庫React-Redux,講解之前,先來了解一下什麼是容器元件和傻瓜元件? React-Redux把元件分為容器元件和傻瓜元件(UI元件)。

一、容器元件

容器元件,負責和Redux Store打交道的元件,處於外層。功能:和Redux Store打交道,讀取Store的狀態,用於初始化元件的狀態,同時還要監聽Store的狀態改變;當Store狀態發生變化時,需要更新元件狀態,從而驅動元件重新渲染;當需要更新Store狀態時,就會派發action物件。特徵:
  • 負責管理資料和業務邏輯,不負責UI的呈現
  • 帶有內部狀態
  • 使用Redux的API

二、傻瓜元件

傻瓜元件也叫做UI元件,只專心負責渲染介面的元件,處於內層。功能:根據當前props和state,渲染出使用者介面。特徵:
  • 只負責UI的呈現,不帶有任何業務邏輯;
  • 沒有狀態(即不使用this.state這個變數)
  • 所有資料都由引數(this.props)提供;
  • 不使用任何Redux的API;
簡單一句話:UI元件負責UI的呈現,容器元件負責管理資料和邏輯。下邊是容器元件和傻瓜元件的分工圖:

三、React-Redux

React-Redux提供了兩個最主要的功能:
  • connect:連線容器元件和傻瓜元件;
  • Provider:提供包含store的connect;

1、connect

語法如下:
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home)
接收兩個引數mapStateToProps和mapDispatchToProps,執行結果依然是一個函式,所以才在最後又加一個圓括號,把connect函式執行的結果立即執行,這一次引數是Home這個傻瓜元件。這裡有兩次函式執行,第一次是connect函式的執行,第二次是把connect函式返回的函式再次執行,最後產生的就是容器元件。作為容器元件,要做的工作無外乎兩件事:
  • 把Store上的狀態轉化為內層傻瓜元件的prop;
  • 把內層傻瓜元件中的使用者動作轉化為派送給Store的動作。
一個是內層傻瓜物件的輸入,一個是內層傻瓜物件的輸出。因此,connect的完整API如下:
import { connect } from 'react-redux'
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home)

(1) mapStateToProps

mapStateToProps是一個函式,它建立一個從外部的state物件到UI元件的props物件的對映關係。
function mapStateToProps(state) {
  return {
    number: state.count.number
  }
}
上面程式碼中,mapStateToProps是一個函式,接受state作為引數,返回一個物件。這個物件有一個number屬性,代表UI元件的同名引數,後面的count也是一個函式,可以從state算出number的值。下面就是count的一個例子:
import { combineReducers } from 'redux'
const initialState={
    number:2
};
function update(state = initialState, action) {
    switch (action.type) {
        case 'INCREASE':
            console.log("INCREASE");
            console.log(state);
            return {
                number: state.number+action.payload 
            };
        case 'DECREASE':
            console.log("DECREASE");
            console.log(state);
            return {
                number:state.number-action.payload  
            };
        default:
            return state;
    }
}
export default combineReducers({
    count: update,
})
mapStateToProps會訂閱Store,每當state更新的時候,就會自動執行,重新計算UI元件的引數,從而觸發UI元件的重新渲染。 mapStateToProps的第一個引數總是state物件,還可以使用第二個引數,代表容器元件的props物件。
const mapStateToProps = (state, ownProps) => {  
    return {    
        active: ownProps.filter === state.visibilityFilter  
    }
}
使用ownProps作為引數後,如果容器元件的引數發生變化,也會引發UI元件重新渲染。

(2) mapDispatchToProps

mapDispatchToProps是connect函式的第二個引數,用來建立UI元件的引數到store.dispatch方法的對映。也就是說,它定義了哪些使用者操作應該當做Action傳給Store。
function mapDispatchToProps(dispatch) {
  return {
    setIncrease: (state) => dispatch(state),
    setDecrease: (state) => dispatch(state)
  }
}

2、Provider

connect方法生成容器元件以後,需要讓容器元件拿到state物件,才能生成UI元件的引數。Provider就是把我們用Redux建立的store傳遞到內部的其他元件,讓內部元件可以享有這個store並提供對state的更新。
import React, { Component } from 'react';
import { createStore} from 'redux'
import { Provider } from 'react-redux'
import {BrowserRouter } from 'react-router-dom';
import { Route } from 'react-router'

import reducers from '../reducer/index.js'
import  App from '../views/App.js'
import  Home from '../views/Home.js'
import  Another from '../views/Another.js'

const store = createStore(reducers);

export default class RouterIndex extends Component {
  render() {
    return ( 
        <Provider store={store}>
          <BrowserRouter>
            <App path="/App" component={App}>
              <Route path="/App/home" component={Home} />
              <Route path="/App/another" component={Another} />
            </App>
          </BrowserRouter>
        </Provider>
    )
  }
}
文中主要用到了react-redux和react-router兩個外掛
  • react-redux實現元件之間的通訊;
  • react-router實現頁面之間的跳轉;