Redux 學習總結筆記

陳惠超發表於2017-04-12

專案驅動是學習框架非常高效的一種方式。
學習 redux 全家桶推薦 react-douban:一個 React + Redux + React-Router 完整專案

該筆記主要是下面三部分:

  • Redux 介紹、基本概念和API和工作流程
  • 中介軟體原理介紹及使用
  • redux-thunk 的用法

Redux 介紹

Redux是什麼?有什麼作用?

Redux是一個管理狀態容器,將整個前端應用的狀態都統一到一個地方管理。通過單一資料流操作,來實現單一狀態。使得前端應用更加方便的管理狀態。

核心概念

整個state就是一個object,可以將store理解為前端的資料庫,沒有setter,不能直接更改。
如果要更改state,則需要dispatch an action。而 action 則是一個物件,用於描述提交了什麼操作,而不涉及對 state 具體的操作。
強制使用action來改變每一次的state,可以讓我們更加容易追蹤到每次state的變化。
而 Reducer 則是用來將 Action 和 State 串起來的一個函式。用於具體處理對 state 的改變。

以上的過程差不多就是整個 Redux 的思想。

Redux 三大原則

Single source of truth(單一資料來源)

在你的應用中state儲存在一個 object tree,而且這個object tree 在該應用中是唯一一個的。
將所有state存在於應用中唯一一個object tree 帶來的好處是:可以實現開發環境下的儲存狀態的歷史狀態,實現Undo/Redo等功能。

State is read-only(State 只讀性)

改變 state 的唯一方式就是觸發一個 action(action 是一個用於描述發生了什麼的物件)

Changes are made with pure functions(使用純函式進行更改)

為了描述action 如何具體改變 state tree,你需要編寫reducers。Reducer 只是一些純函式。
Reducer 接收 state 和 action 作為引數,並返回新的 state。

基本概念和api

Store

Store就是儲存資料的地方,可以看出是一個容器,整個應用就只能有一個store。Redux提供createStore()函式來生成store

import {createStore} from 'redux'

const store = createStore(app);複製程式碼

State

store 某個節點對應的資料集合就是state。可以通過store.getState()獲得。
Redux 規定,一個state對應一個View。State相同,則View相同。

Action

State 的變化會導致 View 的變化。但是使用者接觸不到State,只能接觸到View。所以State的變化必須是View導致的。Action就是View發出的通知,表示State要發生改變了。
Action是一個物件,其中type屬性是必須的,表示Action的名稱。其他屬性隨意。

Action Creator

用於生成Action 的函式。

store.dispatch()

store.dispatch()是View發出Actiion 的唯一辦法。

import {createStore} from 'redux'
const store = createStore(fn);
store.dispatch(addTodo(text))複製程式碼

Reducer

Store 收到Action之後,必須給出一個新的State,這樣才能使View發生變化。這種State的計算過程叫做Reducer。
Reducer 是一個函式,它接受Action和當前的state作為引數,返回一個新的state。
整個應用的初始狀態,可以作為state的預設值。

Reducer還可以進行拆分,然後通過combineReducers方法,結合成一個大的Reducer。

Redux工作流程

首先使用者發出Action。

store.dispatch(action)複製程式碼

然後store自動呼叫Reducer,並且傳入兩個引數:當前的state收到的Action. Reducer 會返回新的state。

let nextState = reducer(previousState, action)複製程式碼

State一旦變化,Store就會呼叫監聽函式。Listener可以通過store.getState()得到當前狀態。

第二部分:redux 中介軟體

中介軟體與非同步操作

Redux解決了同步狀態更新的問題,但是非同步操作卻沒有解決。
如果要 使Reducer在非同步操作結束後自動執行,必須使用中介軟體。

applyMiddleware

createStore()方法包含了引數applyMiddleware(),
它是Redux的原生方法,作用是 將所有的中介軟體組成一個陣列,依次執行

非同步操作的基本思路

非同步操作需要發出三種Action

  • 請求發起時的Action
  • 請求成功時的Action
  • 請求失敗時的Action

所以流程也很清楚:

  1. 操作開始時,dispatch action,觸發State更新為正在操作狀態
  2. 操作結束後 再次 dispatch action,獲取結果

解決方案:
寫出一個返回函式的 Action Creator,然後使用redux-thunk中介軟體改造store.dispatch

import {createStore, applyMiddleware} from 'redux'
import thunk from 'react-thunk'

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
)

export function fetchPost() {

}
export function requestPost(){}

export function receivePost(){}

export function handleError(err) {

}

export function requstAync() {
  return function(dispatch){
    // 請求發起時 dispatch action
    dispatch(requestPost())
    // 這裡的fetchPost 是一個Promise
    return fetchPost()
    .then(response => response.json())
    .then(json =>
     // 請求成功時 dispatch action
      dispatch(receivePost())
    )
    .catch(err =>
     // 請求錯誤時 dispatch action
      dispatch(handleError(err))
    )
  }
}複製程式碼

第三部分:redux-thunk用法

React-Redux將元件分為兩種:

  • UI元件(純元件)
  • 容器元件

UI元件特點

  • 只負責UI顯示,不帶任何邏輯
  • 無狀態元件
  • 所有資料都是通過props提供
  • 不使用任何Redux的API

容器元件

  • 負責管理資料和業務邏輯,不負責UI顯示
  • 帶有內部狀態
  • 使用Redux API

如果遇到一個元件既有UI和業務邏輯時,需要拆分成下面的結構:
外面是一個容器元件,裡面包含若干個UI元件。容器元件負責與外部的通訊、傳遞資料給UI元件。
UI元件則負責頁面顯示。

connect

用於從UI元件生成容器元件。可以這麼來理解 connect 的作用。
connect 就是將 state 上的 props(屬性)和 方法(dispatch)新增到對應的 UI元件上。

import {connect} from 'react-redux'
import {TodoList} from './TodoList'
export default connect()(TodoList)複製程式碼

上面的程式碼就將UI元件 TodoList 轉換為一個容器元件。
每個容器元件需要定義兩方面的資訊:

  • 輸入邏輯:外部的資料(即state物件)如何轉換為 UI 元件的props
  • 輸出邏輯:使用者發出的動作如何變為 Action 物件,從 UI 元件傳出去

完整的connect 方法的API如下:

import {connect} from 'react-redux'
import {TodoList} from './TodoList'

function mapStateToProps(state){
  return{
    // do something
  }
}

function mapDispatchToProps(dispatch){
  return{
    // do something
  }
}
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)複製程式碼

相關文章