react-thunk 浅析

"thunk" 是什么?

单词“thunk”是一个编程术语,意思是“一段做延迟工作的代码”。不需要现在执行一些逻辑,我们可以编写一个函数体或代码,用于以后执行这些工作。

特别是对于Redux来说,“thunks”是一种编写带有内部逻辑的函数的模式,它可以与Redux存储的调度和getState方法交互。

使用thunks需要将Redux -thunk中间件作为配置的一部分添加到Redux存储中。

Thunks是在Redux应用程序中编写异步逻辑的标准方法,通常用于获取数据。但是,它们可以用于各种任务,并且可以包含同步和异步逻辑。

如何使用

thunk函数是接受两个参数的函数:Redux store分派方法和Redux store getState方法。应用程序代码不会直接调用Thunk函数。相反,它们被传递给store.dispatch():

const thunkFunction = (dispatch, getState) => {
  // logic here that can dispatch actions or read state
}

store.dispatch(thunkFunction)

一个thunk函数可以包含任何逻辑,同步或异步,并且可以在任何时候调用dispatch或getState。
Redux代码通常使用动作创建者来生成动作对象以进行分派,而不是手工编写动作对象,我们通常使用thunk动作创建者来生成被分派的thunk函数,这与Redux代码通常使用动作创建者来生成动作对象的方式相同。一个thunk动作创建者是一个函数,它可能有一些参数,并返回一个新的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))
  }
}

Thunk函数和动作创建者可以使用function关键字或箭头函数来编写——这里没有什么有意义的区别。同样的fetchTodoById thunk也可以用箭头函数来写,像这样:

export const fetchTodoById = todoId => async dispatch => {
  const response = await client.get(`/fakeApi/todo/${todoId}`)
  dispatch(todosLoaded(response.todos))
}

在这两种情况下,thunk都是通过调用动作创建者来发送的,与你发送任何其他Redux动作的方式相同:

function TodoComponent({ todoId }) {
  const dispatch = useDispatch()

  const onFetchClicked = () => {
    // Calls the thunk action creator, and passes the thunk function to dispatch
    dispatch(fetchTodoById(todoId))
  }
}

使用场景

由于thunks是一种通用工具,可以包含任意逻辑,因此可以用于各种各样的目的。最常见的用例有:

  • 将复杂的逻辑移出组件
  • 发出异步请求或其他异步逻辑
  • 编写需要在一行或一段时间内调度多个操作的逻辑
  • 编写需要访问的逻辑在getState中做出决定或包含其他状态值

源码逻辑

function createThunkMiddleware(extraArgument) {
  const middleware =
    ({ 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
}

根据自定义一个redux中间件

function createThunkMiddleware(extraArgument) {
  // ThunkMiddleware
  return ({ dispatch, getState }: <storeAPI>) => {
    // wrapDispatch
    next =>
    // handleAction
    action => {
      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)
    }
  }
}

image

posted @ 2022-01-18 18:06  远方的少年🐬  阅读(491)  评论(0编辑  收藏  举报