Redux 知識點梳理和實踐

螞蟻哈哈哈發表於2018-06-27

之前在有道雲筆記上寫過一篇 Redux 學習實踐的文章,附帶了一個小 Demo。由於一段時間沒看 Redux,加上之前缺乏足夠的練習,現在想重構個人部落格,使用 Redux 進行狀態。現在不得不回頭再看看 Redux 相關東西。這裡順便記錄下學習筆記,一來便於回顧,二來希望對他人有所幫助。筆記同步寫在個人部落格網站

這篇文章是知識點的梳理,如果你對 Redux 的基礎有一定了解,閱讀起來可能比較合適。

什麼是 Redux?

Redux 可以說是 Flux 架構思想的最佳實踐方案,用於對大型、複雜、多資料來源的 React 進行資料管理。遵循 Redux 的設計原則,再配合 React 容器元件、展示元件分離的程式碼組織原則,可以讓我們的專案結構清晰,資料流清晰,十分利於專案的維護開發。

Redux 設計的三大原則

  1. 單一的資料來源,所有的資料儲存在一個物件中。
  2. 狀態只讀,Reducer 根據 store dispatch 的 action 型別返回一個新的狀態,不修改原來的狀態。
  3. 狀態修改均由純函式完成。

關於這三大原則的深入理解建議參考 《深入React技術棧》、《深入淺出React和Redux》

淺談 Redux 的工作過程(和 MVC 的主要區別)

有 MVC 框架使用經驗的同學應該清楚,MVC 的工作過程是這樣:view 層將使用者行為傳遞到 controller 中的action, controller 中的 action 和 Model 層互動運算元據,返回到 view。通常 MVC 框架的實現 M 和 V 層是可以互動的,這樣資料就不是單向流動,這種設計很多場景下很靈活,寫起來很爽快,但是要專案過大,專案資料流複雜,專案維護就不爽了。

Redux 則嚴格遵循上面提到的設計三大原則,工作過程是這樣的:view 層觸發一個 action,這個 action 由 store.dispatch(action) 傳遞給 reducer,reducer 根據 previousState 和 action type 返回一個新的 state(不修改資料), 如此實現了資料的變更。

Redux 核心 API

上面 Redux 的工作過程提到了 Redux 有 store、action、reducer 這些概念,這些都是 Redux 對外提供的核心 API,我們來看看他們分別是幹嘛的。

  1. store

    store 作為整個應用資料的唯一來源,用於儲存資料和 dispatch action。store 使用 Redux 提供的 createStore 方法來生成。

    import { createStore } from 'redux';
    let store = createStore(reducer)
    複製程式碼

    createStore 接受一個 reducer 作為引數,返回一個 store 物件。store 物件包含 4 中方法:

    getState():// 用於獲取 store 中當前的狀態
    dispatch():// 用於分發 action,這個是改變 store 中資料的唯一方式
    subscribe(listener):// 註冊一個監聽者,在 store 發生變化時被呼叫
    replaceReducer(nextReducer):///更新當前 store 中的 reducer
    複製程式碼
  2. reducer

    reducer 本質上是一個函式,這個函式能接受一個 action 和一箇舊的狀態(previousState),根據 previousState 和 action 返回新的狀態

    reducer(previousState, action) => newState
    複製程式碼

reducer 必須是一個純函式,不能修改原來狀態,關於純函式的概念請閱讀其他資料學習。

  1. action

    reducer 的 action 本質上是一個 javaScript 物件,這個物件必須有一個 type 屬性,用來表明 action 的型別,還可以有 payload, error, meta 屬性。關於 action 物件的屬性,社群有個規範,可以參考github.com/redux-utili…

    const action = {
        type: 'ADD_TODO',
        payload: 'todo'
    }
    複製程式碼

    reducer 就是根據 action type 屬性來決定返回新的 state。

先睹為快

我在學習 Redux 的時候,看了很多文件,認為對 Redux 的概念瞭然於胸,但是動手寫第一個小 Demo 的時候仍然覺得很難下手,可能是 Redux 這些概念對我而言太新。這裡給出我寫的第一個小 Demo。

這個 Demo 實現了點選按鈕讓數字加一減一的功能,沒有任何複雜度,單純的是為了瞭解 actionstorereducer 的具體作用和協作關係。

Demo 地址: github.com/wewin11235/…

為了便於觀察,Demo 的程式碼都丟在了一個檔案裡,在實際開發中,一定要遵循好的程式碼組織原則。

import React from 'react';
import ReactDOM from 'react-dom';

// 建立 action
// action 是 javaScript 物件,是使用者行為的抽象,必須包含一個 stype 欄位
// 根據 Demo 需要實現記數功能,抽象出兩種 action, 一種表示加,一種表示減
const incream_action = { type: 'INCREAM' };
const decream_action = { type: 'DECREME' };

// 建立 reducer
// reducer 接受一個 previousState 和 action 返回一個新的 state
const reducer = (state=0, action) => {
  switch (action.type) {
    case incream_action.type:
      return state + 1;
    case decream_action.type:
      return state - 1;
    default:
      console.log('default');
      return state;
  }
}

// 建立 store
// store 建立使用 createStore(reducers)
// createStore 由 redux 提供
import { createStore } from 'redux';
let store = createStore(reducer);

// 建立計陣列件
class Counter extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { count, doIncrement, doDecrement } = this.props
    return(
      <div>
        <span>{count}</span>
        <button onClick={doIncrement}>+</button>
        <button onClick={doDecrement}>-</button>
      </div>
    )
  }
}

const render = () => ReactDOM.render(
  <Counter
    count={store.getState()}
    doIncrement={() => store.dispatch(incream_action)}
    doDecrement={() => store.dispatch(decream_action)}
  />,
  document.getElementById('root')
);

render();

// 為了能在 store 發生變化後能重新整理頁面,需要給 store 註冊一個監聽事件
// store 變化後,重新整理頁面
store.subscribe(render);
複製程式碼

最小 Redux 應用誕生。

歡迎指正,補充!

相關文章