專案驅動是學習框架非常高效的一種方式。
學習 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
所以流程也很清楚:
- 操作開始時,dispatch action,觸發State更新為正在操作狀態
- 操作結束後 再次 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)複製程式碼