mominger / blog

Tech blog
45 stars 3 forks source link

Analysis of Redux-thunk source code #37

Open mominger opened 2 years ago

mominger commented 2 years ago

The upper part is the English version, and the lower part is the Chinese version, with the same content. If there are any wrong, or you have anything hard to understand, pls feel free to let me know.many thx.

Overview

Analyze the principle and source code of Redux-thunk

1. Invoke flow

flow

2 How to use

in store.js

import thunk from 'redux-thunk';
const store = () => createStore(rootReducer, applyMiddleware(thunk));

in action.js

export const fetchTodos = () => dispatch => (
  fetchTodos().then(todos => dispatch({
  type: GET_TODOS,
  todos
}))
);

in ui component

store.dispatch(fetchTodos())

After using redux-thunk, redux's original dispatch({type:xxx,...}) supports dispatch(fn(...))

3. Source code

source code


function createThunkMiddleware<
State = any,
BasicAction extends Action = AnyAction,
ExtraThunkArg = undefined
(extraArgument?: ExtraThunkArg) {
// Standard Redux middleware definition pattern:
// See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware
const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
({ dispatch, getState }) =>
next =>
action => {
// The thunk middleware looks for any functions that were passed to `store.dispatch`.
// If this "action" is really a function, call it and return the result.
if (typeof action === 'function') {
// Inject the store's `dispatch` and `getState` methods, as well as any "extra arg"
return action(dispatch, getState, extraArgument)
}
  // Otherwise, pass the action down the middleware chain as usual
  return next(action)
}

return middleware }

> The key is the line if (typeof action === 'function')
> If action is a function, invoke this function, otherwise go into the next middleware

### 4 Simplified version

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

return next(action); }; export default thunk

> Without redux-thunk, there are only two ways to deal with the side effects of the request: 1. The View layer (ui component) sends the request first, and invoke store.dispath after getting the response data. 2. send the request in the reducer, and invoke the store.dispatch after getting the response data. 
> Use redux-thunk, you can build actions that support functions

_The following is the Chinese version, the same content as above_

### Overview
> 分析redux-thunk的原理和源码

### 1. Invoke flow
![flow](https://raw.githubusercontent.com/mominger/MyPublicFiles/master/img/20220318095347.png)

### 2  如何使用
in store.js

import thunk from 'redux-thunk'; const store = () => createStore(rootReducer, applyMiddleware(thunk));

in action.js

export const fetchTodos = () => dispatch => ( fetchTodos().then(todos => dispatch({ type: GET_TODOS, todos })) );

在ui组件里

store.dispatch(fetchTodos())

> 使用 redux-thunk 后,redux 原有的 dispatch({type:xxx,...}) 支持 dispatch(fn(...))

### 3. 源码
> [源码](https://github.com/reduxjs/redux-thunk/blob/master/src/index.ts)

function createThunkMiddleware< State = any, BasicAction extends Action = AnyAction, ExtraThunkArg = undefined

(extraArgument?: ExtraThunkArg) { // Standard Redux middleware definition pattern: // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> = ({ dispatch, getState }) => next => action => { // The thunk middleware looks for any functions that were passed to store.dispatch. // If this "action" is really a function, call it and return the result. if (typeof action === 'function') { // Inject the store's dispatch and getState methods, as well as any "extra arg" return action(dispatch, getState, extraArgument) }

  // Otherwise, pass the action down the middleware chain as usual
  return next(action)
}

return middleware }

> 关键是 if (typeof action === 'function') 这一行

> 如果 action 是个函数,就调用这个函数,否则就传给下一个中间件

### 4 简化写法

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

return next(action); }; export default thunk


>  不用redux-thunk,只能通过2种方式处理请求副作用: 1.View层(ui组件)先发请求,拿到响应数据后调用store.dispath   2.在reducer里执行请求,拿到数据后调用store.dispatch
> 有了redux-thunk 则可以写支持函数的action