Redux Middleware翻成中介軟體,在dispatch action之後到執行reducer之間,可以執行多個middleware,就像接力賽一樣將action交棒給middleware,再交棒給下一個middleware,最後才觸發reducer
在middleware階段可以觀察是哪個action觸發以及state的變化紀錄,也可以在這裡處理非同步的問題,因為redux本身無法處理非同步的action,像是dispatch一個action是call api這類的行為
首先要先引入applyMiddleware
import { applyMiddleware } from 'redux'
第一次看到這樣寫覺得很神奇,其實就是呼叫一個函式會再回傳一個函式 ES6 Arrow Function的寫法
const logMiddleWare = store => next => action => {
console.log("dispatching", action);
next(action);
}
換成一般的function寫法就會是這樣,有波動拳的既視感
function logMiddleWare(store)
function wrapDispatchLog(dispatch) {
return function(action) {
dispatch(action)
}
}
}
以下就是一個簡易版的Middleware,將定義好的middleware傳入redux提供的applyMiddleware,再傳入createStore()
import { createStore, applyMiddleware } from 'redux'
const logMiddleWare = store => next => action => {
console.log("dispatching", action);
next(action);
}
const logAddOneMiddleware = store => next => action => {
if (action.type === 'ADD_ONE') {
console.log(`state change ${JSON.stringify(store.getState())}`);
}
next(action);
}
const store = createStore(reducer, applyMiddleware(logMiddleWare, logAddOneMiddleware));
logMiddleWare為第一個middleware,透過store拿到action後 ,再呼叫next方法將action往下交棒給第二個 middleware logAddOneMiddleware,最後觸發reducer
就會看到在更動資料前,會印出action以及變動前的state
以上就是Redux Middleware的基本概念,明天會介紹Redux thunk來如何解決aciton非同步的問題
我的理解:
let add1 = x => y => z => x + y + z //add1 = (x)=>{ return (x)=>{ (y) => { (z) => { x + y + z } } } }
let add2 = add1(1) //add2 = (y)=>{ return (y)=>{ (z) => { 1 + y + z } } }
let add3 = add2(2) //add3 = (z)=>{ return 1 + 2 + z }
add3(3) //add3 = (3)=>{ return 1 + 2 + 3 }
function add1(x){
//此時add2能看到x,所以不用具體從參數帶入
function add2(y){
//此時add3能看到x,y,所以不用具體從參數帶入
return add3(z){
x + y + z
}
}
}
//=============================//
const logMiddleWare = store => next => action => {
console.log("dispatching", action);
next(action);
}
function logMiddleWare(store){
//此時Func1能看到store,所以不用具體從參數帶入
function Func1(next){
//此時Func2能看到store,next,所以不用具體從參數帶入
function Func2(action){
next(action);
}
}
}
//在Redux thunk中,Next其實可以當作dispatch
//在Redux thunk中,store其實可以當作State
//=======Redux thunk源碼========//
function createThunkMiddleware(extraArgument) {
// 這是 middleware 基本的寫法
return ({ dispatch, getState }) =>
(next) =>
(action) => {
// action 就是透過 action creators 傳進來的東西,在 redux-thunk 中會是 async function
if (typeof action === 'function') {
// 在這裡回傳「執行後的 async function」
return action(dispatch, getState, extraArgument);
}
// 如果傳進來的 action 不是 function,則當成一般的 action 處理
return next(action);
};
}
//=======在Redux thunk範例========//
// fetchTodoById is the "Thunk Action Creator"
export function fetchTodoById(todoId) {
// fetchTodoByIdThunk is the "Thunk Function"
return async function fetchTodoByIdThunk(dispatch, getState) {
const response = await client.get(`/fakeApi/todo/${todoId}`)
dispatch(todosLoaded(response.todos))
}
}
//use
function TodoComponent({ todoId }) {
const dispatch = useDispatch()
const onFetchClicked = () => {
// Calls the thunk action creator, and passes the thunk function to dispatch
dispatch(fetchTodoById(todoId))
}
}
//=======將範例套用到源碼中========//
function createThunkMiddleware(todoId) {
// 這是 middleware 基本的寫法
return ({ dispatch, getState }) =>
(dispatch) =>
(fetchTodoById) => {
// action 就是透過 action creators 傳進來的東西,在 redux-thunk 中會是 async function
if (typeof fetchTodoById=== 'function') {
// 在這裡回傳「執行後的 async function」
return fetchTodoById(dispatch, getState, todoId);
}
// 如果傳進來的 action 不是 function,則當成一般的 action 處理
return dispatch(fetchTodoById);
};
}