gracekrcx / weekly-notes

4 stars 0 forks source link

[2020-03-21] Redux-Thunk(middleware) #82

Open gracekrcx opened 4 years ago

gracekrcx commented 4 years ago

redux-thunk

flow

middleware 是什麼

action -> middleware -> another action 重點

  1. action in, action out(action 進入 middleware, 出 middleware 發出另一個 action)
  2. side effect 都在 middleware 發生(call api 也是一個 side effect )

redux-thunk 是什麼

dispatch 一個 promise,middleware 幫你執行 redux-thunk 如果偵測到 dispatch 的 action 是回傳一個 function,他就會把 dispatch 傳入 function,然後執行 function

  1. 在 action creator 裡會 return 一個 function

const INCREMENT_COUNTER = 'INCREMENT_COUNTER';

// 一般回傳 object
function increment() {
  return {
    type: INCREMENT_COUNTER,
  };
}

// 回傳 function
function incrementAsync() {
  return (dispatch) => {
    setTimeout(() => {
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    }, 1000);
  };
}
  1. 參數除了 dispatch 還有 getState,目前看起來是可以拿到 global 的 state,實際處理的時候 log 看看 ( returns a function to perform conditional dispatch:)
function incrementIfOdd() {
  return (dispatch, getState) => {
    const { counter } = getState();  // getState() 得到一個 object

    if (counter % 2 === 0) {
      return;
    }

    dispatch(increment());
  };
}

把呼叫 api 的行為移到 action creator,好處是可以共用呼叫 api function,也讓 component 單純是 component,規模不大的案子這樣寫也可以

// container.js

const mapDispatchProps = dispatch => {
 retutrn {
  getPostList: ()=>{
   actions.getPostList(dispatch)
  }
 }
}

// actions.js

export const getPostList = (dispatch) => {
 // ... 你要 dispatch 的 action 寫在 action creator
 dispatch(getPosts())  // getPosts() 是一個 action
 WebAPI.getPosts().then(res => {
 dispatch(getPostsSucess(res.data))  //getPostsSucess() 是一個 action
 }) 
}

使用 thunk 改寫

// container.js

const mapDispatchProps = dispatch => {
 retutrn {
  getPostList: ()=> {
    // 可以想成 dispatch( 一個 function )
   dispatch(actions.getPostList())
  }
 }
}

// actions.js

export const getPostList = () => {
 return function(dispatch){
  dispatch(getPosts())  
  WebAPI.getPosts().then(res => {
   dispatch(getPostsSucess(res.data)) 
  }) 
 }
}

redux-thunk 的原始碼

重點在第三行,如果 action 是個 function 就會幫你執行。

另外 redux-saga 和 redux-observable,都是把邏輯從 action 裡面拿掉,再拆分出來一層。保持 action 都是 pure action(純 JS 物件),方便測試。這兩套的底層概念是一樣的,就是 pure action in, pure action out。

redux-saga 與 redux-observable 這兩套與 redux-thunk 跟 redux-promise 最不一樣的地方。在這兩套裡面,action 一定是 pure action,不會是 function 也不會是 promise。

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => (next) => (action) => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

img

參考文章

後設鐵人 Day29:S12z

gracekrcx commented 4 years ago

What is the difference between redux-thunk and redux-promise?