Redux-thunk 是一个 Redux 的中间件,它允许我们在 Redux 的 action 创建函数中返回一个函数而不是一个对象。返回的这个函数可以接受其它引用数据,例如 dispatch
、getState
,并在这个函数中执行异步逻辑,并 dispatch 其它的 action,从而最终改变应用的状态。
在本篇文章中,我们将对 Redux-thunk 中的源码进行深入的解读,并希望读者在阅读本篇文章之后,能够对 Redux-thunk 的内部工作原理有更加深入的理解,并且可以在自己的项目中更好地使用和调试 Redux-thunk。
关于 Redux-thunk
在 Redux 应用中,我们通常会通过在组件内部定义 action 创建函数来 dispatch action,例如:
const increment = () => ({ type: 'INCREMENT' }) const decrement = () => ({ type: 'DECREMENT' })
这样的 action 可以在组件内部通过调用 dispatch 来改变应用的状态。
但是在应用中,我们有时会遇到需要处理异步操作的情况,例如在用户登录操作中,需要先向服务器发送请求,等到服务器返回结果之后再 dispatch action,才能真正地改变应用的状态。
这个时候 Redux-thunk 中间件就派上用场了。
通过在 action 创建函数中返回一个函数,示例如下:
const loginUser = (username, password) => dispatch => { dispatch({ type: 'LOGIN_REQUEST' }) api.login(username, password) .then(() => dispatch({ type: 'LOGIN_SUCCESS' })) .catch(() => dispatch({ type: 'LOGIN_FAILURE' })) }
在这个示例中,我们返回了一个函数,它接受 dispatch
作为第一个参数,并且在函数体内部执行异步操作,然后 dispatch 其它的 action,最后返回了一个 Promise 对象,方便我们在外部使用 then
方法来判断操作是否完成。
Redux-thunk 通过将返回的函数注入 dispatch
、getState
、extraArgument
等参数,让我们可以灵活地进行异步逻辑的处理。
深入 Redux-thunk 源码
接下来,我们将深入 Redux-thunk 中间件的源码,了解其内部实现。
首先,在使用 Redux-thunk 中间件时,我们通常要先使用 applyMiddleware
函数将 Redux-thunk 中间件注册到应用中:
import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' const store = createStore( reducer, applyMiddleware(thunk) )
在 applyMiddleware
函数中,会对传入的中间件进行格式化,使得它们可以正确地被应用。
-- -------------------- ---- ------- ------ ------- -------- ------------------------------- - ------ ----------- -- --------- -- - -- --- ----- ----- - -------------------- --- -------- - -- -- - ----- --- ------ ------------ ----- ------------ ---- ---------- -- --- -------- - - ------ ---------- ----- --- -- ------- -- ---- ---------- - - ----- ------------- - - --------- --------------- --------- --------- -- ----------------- - -- --- - -
在这个函数中,我们可以看到在创建 Redux 的 store
时,会先定义一个 dispatch
方法,这个方法的内部实现是抛出一个错误。
接着,我们将 getState
和这个 dispatch
方法以 middlewareAPI
的形式注入到 next
函数中:
const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
在此过程中,middlewares
是一个包含所有中间件的数组,在 Redux-thunk 应用中,它的值为 [thunk]
。
在每一个中间件函数中,我们都可以接受一个 { getState, dispatch }
形式的参数对象,在 Redux-thunk 应用中也是一样的。
接着进入到最重要的 Redux-thunk 源码部分:
-- -------------------- ---- ------- -------- ------------------------------------ - ------ -- --------- -------- -- -- ---- -- ------ -- - -- ------- ------ --- ----------- - ------ ---------------- --------- --------------- - ------ ------------- -- - ----- ----- - ------------------------ ----------------------- - ---------------------- ------ ------- ------
在函数 createThunkMiddleware
中,我们定义了一个接受 extraArgument
参数的函数,并在它的返回值中定义了一个三级嵌套的函数结构:
- 第一层函数接受的参数为注入到这个中间件中的参数对象
{ dispatch, getState }
。 - 第二层函数接受的参数为应用中的下一个中间件的
next
函数,该函数用于执行下一个中间件或最终的dispatch
函数。 - 第三层函数接受的参数为当前的 action,如果当前的 action 是一个函数,则说明这是一个异步操作,我们需要通过执行返回的函数来修改应用的状态。
在 createThunkMiddleware
函数中,我们首先定义了一个函数 thunk
,返回值即为上述结构的第一层函数,并且定义了一个名为 thunk.withExtraArgument
的函数,用于返回一个接受额外参数 extraArgument
的 Redux-thunk 中间件函数。
在第一层函数中,我们返回了一个函数,这个函数接受 next
作为参数,并且在其内部返回了一个函数,这个函数接受 action
作为参数。
在对传入的 action
进行判断之后,如果它是一个函数,我们将会执行它,并在参数中注入了 dispatch
、getState
和 extraArgument
参数,从而使得这个函数可以通过调用 dispatch
函数来 dispatch 其它的 action,最终改变应用的状态。
在执行这个函数之后,我们将其返回值作为异步操作的 Promise 对象,方便在外部对异步操作是否完成进行判断。
如果 action
不是一个函数,我们将会使用 next
函数来将它转发给下一个中间件来处理,并最终传递到最终的 dispatch
函数。
Redux-thunk 在实际开发中的应用
在实际的开发中,我们通常会通过 async/await 或者 Promise 的方式来处理对象的异步操作,例如:
-- -------------------- ---- ------- ------ --- ---- ------- ----- --------- - ---------- --------- -- ----- -------- -- - ---------- ----- --------------- -- --- - ----- ------------------- --------- ---------- ----- --------------- -- - ----- ----- - ---------- ----- --------------- -- - -
在这个例子中,我们使用了 async/await 的方式来处理对象的异步操作,并且在 catch 中 dispatch 其它的 action,使用了最新的语法特性,更加优美和易读。
总结
Redux-thunk 是一个方便我们处理 Redux 异步操作的中间件,它通过在 action 创建函数中返回一个函数的形式,支持异步操作以及 dispatch 其它的 action,并提供了一些额外的参数来支持更加灵活的处理异步逻辑。
在 Redux-thunk 的源码中,我们深入了解了中间件的实现方式,并且可以更清晰地了解到 Redux-thunk 是如何拦截 action 并处理异步逻辑的。
在实际开发中,我们可以使用最新的语法特性来编写异步操作代码,并且可以更好地利用 Redux-thunk 的特性,来轻松地处理复杂的异步逻辑。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64cdea89b5eee0b5255dd1c8