1. 程式人生 > >深入淺出React+Redux(五:React-Redux)

深入淺出React+Redux(五:React-Redux)

前言

React 應用的兩個方法,第一是把一個元件拆分為容器元件和傻瓜元件,第二是使用 React 的 Context 來提供一個所有元件都可以直接訪問的 Context,也不難發現,這兩種方法都有套路,完全可以把套路部分抽取出來複用,這樣每個元件的開發只需要關注於不同的部分就可以了 。

實際上,已經有這樣的一個庫來完成這些工作了,這個庫就是 react-redux 。

(一)React-Redux 基本概念

現在提及React-Redux的最要功能:

connect : 連線容器元件和無狀態元件(stateless)
Provider : 提供包含 store 的 context(提供React-Router傳遞)。

(二)connect

我們以Counter元件為例子。

import React from 'react';
import {connect} from 'react-redux';
function Counter({caption, onIncrement, onDecrement, value}) {
    ...
}

// 容器元件,
// 把store上的狀態轉化為內層傻瓜元件的prop,
// 把內層傻瓜元件中的使用者動作轉化為派送給store的動作
export default connect(mapStateToProps, mapDispatchToProps)(Counter);

第一眼看去,會讓人覺得這就類似thunk函式, 在函式執行完成再次返回一個函式 。

其實, connect 是 react-redux提供的一個方法,這個方法接收兩個引數 mapStateToProps 和 mapDispatchToProps ,執行結果依然是一個函式,所以才可以在後面又加一個圓括號,把 connect 函式執行的結果立刻執行,這一次引數是 Counter 這個傻瓜元件。

這裡有兩次函式執行,第一次是 connect 函式的執行,第二次是把 connect 函式返回的函式再次執行,最後產生的就是容器元件,功能相當於上一章的CounterContainer 。

總結:
這個 connect 函式具體做了什麼工作呢?
作為容器元件,要做的工作無外乎兩件事:

把 Store 上的狀態轉化為內層傻瓜元件的 prop;
把內層傻瓜元件中的使用者動作轉化為派送給 Store 的動作 。

這兩個工作一個是內層傻瓜物件的輸人,一個是內層傻瓜物件的輸出 。

(1)mapStateToProps

Counter 元件對應的 mapStateToProps 函式程式碼如下:

function mapStateToProps(state, ownProps) {
  const { demo } = state;
  return {
    value: demo[ownProps.caption]
  }
}

上面程式碼。mapStateToProps接受2個引數,一個是store的state,一個是元件輸入的props(ownProps),使用ownProps作為引數後,如果容器元件的引數發生變化,也會引發 UI 元件重新渲染。

(2)mapStateToProps

mapDispatchToProps是connect函式的第二個引數,用來建立 UI 元件的引數到store.dispatch方法的對映。它可以是一個函式,也可以是一個物件。

Counter 元件對應的 mapStateToProps函式程式碼如下:

import * as Actions from '../../actions/demoActions';
function mapDispatchToProps(dispatch, ownProps) {
  return {
    onIncrement: () => {
      dispatch(Actions.increment(ownProps.caption));
    },
    onDecrement: () => {
      dispatch(Actions.decrement(ownProps.caption));
    }
  }
}

上面程式碼。mapDispatchToProps接受2個引數,一個是store的dispatch,負責配合Actions中定義的函式,將使用者的操作應該當作 Action,傳給 Store。一個是元件輸入的props(ownProps)

總結:
從上面程式碼我們可以知道,mapStateToProps 和 mapDispatchToProps 都可以包含第二個引數,代表 ownProps,也就是直接傳遞給外層容器元件的 props 。

前者負責把 Store 上的狀態轉化為內層傻瓜元件的 prop。
後者負責把內層傻瓜元件中的使用者動作轉化為派送給 Store 的動作 。

(三)Provider

雖然我們上章已經實現了一個Provider元件。但是react-redux 的要求更加嚴謹。

比如我們只要求 store 屬性是一個 object,而react-redux 要求 store 不光是一個 object ,而且是必須包含三個函式的 object ,這三個函式分別是。

subscribe
dispatch
getState

擁有上述三個函式的物件,才能稱之為一個 Redux 的 store 。

另外, react-redux 定義了 Provider 的 componentWillReceiveProps 函式,在 React 元件的生命週期中, componentWillReceiveProps 函式在每次重新渲染時都會呼叫到,

react-redux 在 componentWillReceiveProps 函式中會檢查這一次渲染時代表 store 的 prop 和上一次的是否一樣。

如果不一樣,就會給出警告,這樣做是為了避免多次渲染用了不同的
Redux Store 。

每個 Redux 應用只能有一個 Redux Store ,在整個 Redux 的生命週期中都
應該保持 Store 的唯一性 。