iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
1
自我挑戰組

React初心者30天的探索之路系列 第 19

[Day 19] Redux Middleware

  • 分享至 

  • xImage
  •  

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非同步的問題


上一篇
[Day 18] 像是迷霧森林的React Redux
下一篇
[Day 20] 用Redux Thunk 來處理非同步action
系列文
React初心者30天的探索之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
AndrewYEE
iT邦新手 3 級 ‧ 2023-02-07 16:59:49

我的理解:

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);
            };
}

我要留言

立即登入留言