5.基础教程-异步逻辑与数据请求
你将学到
- 如何使用 Redux “thunk” middleware 处理异步逻辑
- 处理异步请求状态的开发模式
- 如何使用 Redux Toolkit
createAsyncThunk
API 来简化异步调用
thunks 与异步逻辑
使用 Middleware 处理异步逻辑
就其本身而言,Redux store 对异步逻辑一无所知,任何异步都必须发生在 store 之外。
Redux middleware 扩展了 store,它允许:
- dispatch action 时执行额外的逻辑(例如打印 action 的日志和状态)
- 暂停、修改、延迟、替换或停止 dispatch 的 action
- 编写可以访问
dispatch
和getState
的额外代码 - 教
dispatch
如何接受除普通 action 对象之外的其他值,例如函数和 promise,通过拦截它们并 dispatch 实际 action 对象来代替
使用 middleware 的最常见原因是允许不同类型的异步逻辑与 store 交互。这允许你编写可以 dispatch action 和检查 store 状态的代码,同时使该逻辑与你的 UI 分开。
Redux 有多种异步 middleware,每一种都允许你使用不同的语法编写逻辑。最常见的异步 middleware 是 redux-thunk
,它可以让你编写可能直接包含异步逻辑的普通函数。Redux Toolkit 的 configureStore
功能默认自动设置 thunk middleware,我们推荐使用 thunk 作为 Redux 开发异步逻辑的标准方式。
早些时候,我们看到了Redux 的同步数据流是什么样子。当引入异步逻辑时,我们添加了一个额外的步骤,middleware 可以运行像 AJAX 请求这样的逻辑,然后 dispatch action。这使得异步数据流看起来像这样:

thunk 函数
将 thunk middleware 添加到 Redux store 后,它允许你将 thunk 函数 直接传递给 store.dispatch
。调用 thunk 函数时总是将 (dispatch, getState)
作为它的参数,你可以根据需要在 thunk 中使用它们。
Thunks 通常还可以使用 action creator 再次 dispatch 普通的 action,比如 dispatch(increment())
:
1 | const store = configureStore({ reducer: counterReducer }) |
为了与 dispatch 普通 action 对象保持一致,我们通常将它们写为 _thunk action creators_,它返回 thunk 函数。这些 action creator 可以接受可以在 thunk 中使用的参数。
1 | const logAndAdd = amount => { |
Thunk 通常写在 “slice” 文件中。createSlice
本身对定义 thunk 没有任何特殊支持,因此你应该将它们作为单独的函数编写在同一个 slice 文件中。这样,他们就可以访问该 slice 的普通 action creator,并且很容易找到 thunk 的位置。
“thunk” 这个词是一个编程术语,意思是 “一段做延迟工作的代码”.
编写异步 Thunks
Thunk 内部可能有异步逻辑,例如 setTimeout
、Promise
和 async/await
。这使它们成为使用 AJAX 发起 API 请求的好地方。
Redux 的数据请求逻辑通常遵循以下可预测的模式:
- 在请求之前 dispatch 请求“开始”的 action,以指示请求正在进行中。这可用于跟踪加载状态以允许跳过重复请求或在 UI 中显示加载中提示。
- 发出异步请求
- 根据请求结果,异步逻辑 dispatch 包含结果数据的“成功” action 或包含错误详细信息的 “失败” action。在这两种情况下,reducer 逻辑都会清除加载状态,并且要么展示成功案例的结果数据,要么保存错误值并在需要的地方展示。
这些步骤不是 _必需的_,而是常用的。(如果你只关心一个成功的结果,你可以在请求完成时发送一个“成功” action ,并跳过“开始”和“失败” action 。)
Redux Toolkit 提供了一个 createAsyncThunk
API 来实现这些 action 的创建和 dispatch,我们很快就会看看如何使用它。
细节说明
如果我们手动编写一个典型的 async thunk 的代码,它可能看起来像这样:
1 | const getRepoDetailsStarted = () => ({ |
提示:
Redux Toolkit 有一个新的 RTK Query data fetching API。 RTK Query 是专门为 Redux 应用程序构建的数据获取和缓存解决方案,可以不用编写任何 thunk 或 reducer 来处理数据获取。
总结
可以编写可复用的“selector 选择器”函数来封装从 Redux 状态中读取数据的逻辑
- 选择器是一种函数,它接收 Redux
state
作为参数,并返回一些数据
Redux 使用叫做“ middleware ”这样的插件模式来开发异步逻辑
- 官方的处理异步 middleware 叫
redux-thunk
,包含在 Redux Toolkit 中 - Thunk 函数接收
dispatch
和getState
作为参数,并且可以在异步逻辑中使用它们
你可以 dispatch 其他 action 来帮助跟踪 API 调用的加载状态
- 典型的模式是在调用之前 dispatch 一个 “pending” 的 action,然后是包含数据的 “sucdess” 或包含错误的 “failure” action
- 加载状态通常应该使用枚举类型,如
'idle' | 'loading' | 'succeeded' | 'failed'
Redux Toolkit 有一个 createAsyncThunk
API 可以为你 dispatch 这些 action
createAsyncThunk
接受一个 “payload creator” 回调函数,它应该返回一个Promise
,并自动生成pending/fulfilled/rejected
action 类型- 像
fetchPosts
这样生成的 action creator 根据你返回的Promise
dispatch 这些 action - 可以使用
extraReducers
字段在createSlice
中监听这些 action,并根据这些 action 更新 reducer 中的状态。 - action creator 可用于自动填充
extraReducers
对象的键,以便切片知道要监听的 action。 - Thunk 可以返回 promise。 具体对于
createAsyncThunk
,你可以await dispatch(someThunk()).unwrap()
来处理组件级别的请求成功或失败。