Redux Essentials 教程:异步逻辑与数据获取
redux 项目地址: https://gitcode.com/gh_mirrors/red/redux
概述
在 Redux 应用中处理异步逻辑是开发复杂应用的关键部分。本文将深入探讨如何在 Redux 中处理异步操作,特别是使用 Redux Toolkit 提供的工具来简化异步流程。
异步逻辑基础
为什么需要中间件
Redux 本身是同步的,它只能同步地派发 action、调用 reducer 更新状态并通知 UI。要处理异步操作(如 API 调用),我们需要中间件来扩展 Redux 的功能。
Redux 中间件可以:
- 在 action 被派发前后执行额外逻辑
- 修改、延迟或阻止 action
- 访问
dispatch
和getState
方法 - 处理非普通 action 对象(如函数或 Promise)
Thunk 简介
Thunk 是一种特殊的 Redux 中间件,允许你编写包含异步逻辑的函数。Redux Toolkit 默认配置了 thunk 中间件,使其成为处理异步逻辑的标准方式。
一个 thunk 函数接收 dispatch
和 getState
作为参数,可以在其中执行异步操作:
const exampleThunk = () => (dispatch, getState) => {
// 异步逻辑
dispatch(someAction())
}
数据获取模式
在 Redux 中获取数据通常遵循以下模式:
- 派发"开始"action,表示请求开始(用于显示加载状态)
- 执行异步请求
- 根据结果派发"成功"或"失败"action
- reducer 处理结果并更新状态
使用 createAsyncThunk
Redux Toolkit 提供了 createAsyncThunk
API 来自动生成处理上述模式的 thunk:
const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
const response = await client.get('/fakeApi/posts')
return response.data
})
createAsyncThunk
会自动生成并派发三种 action:
posts/fetchPosts/pending
- 请求开始posts/fetchPosts/fulfilled
- 请求成功posts/fetchPosts/rejected
- 请求失败
实践:获取帖子数据
状态结构调整
为了跟踪请求状态,我们需要重构 postsSlice 的状态:
const initialState = {
posts: [],
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
error: null
}
创建选择器
封装状态选择逻辑到可重用的选择器函数中:
export const selectAllPosts = state => state.posts.posts
export const selectPostById = (state, postId) =>
state.posts.posts.find(post => post.id === postId)
实现异步 Thunk
使用 createAsyncThunk
创建获取帖子的 thunk:
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
const response = await client.get('/fakeApi/posts')
return response.data
})
处理异步 Action
在 slice 中添加 extraReducers 来处理异步 action:
const postsSlice = createSlice({
name: 'posts',
initialState,
reducers: {
// ...同步 reducers
},
extraReducers(builder) {
builder
.addCase(fetchPosts.pending, (state) => {
state.status = 'loading'
})
.addCase(fetchPosts.fulfilled, (state, action) => {
state.status = 'succeeded'
state.posts = action.payload
})
.addCase(fetchPosts.rejected, (state, action) => {
state.status = 'failed'
state.error = action.error.message
})
}
})
在组件中使用
在组件中派发 thunk 并处理不同状态:
function PostsList() {
const dispatch = useDispatch()
const posts = useSelector(selectAllPosts)
const postStatus = useSelector(state => state.posts.status)
useEffect(() => {
if (postStatus === 'idle') {
dispatch(fetchPosts())
}
}, [postStatus, dispatch])
if (postStatus === 'loading') {
return <div>Loading...</div>
}
// 渲染帖子列表
}
最佳实践
- 封装选择器:将状态选择逻辑封装在选择器中,便于维护
- 明确的请求状态:使用枚举值而非布尔值跟踪请求状态
- 避免重复请求:检查状态后再决定是否发起请求
- 错误处理:始终处理可能的错误情况
- UI 反馈:根据请求状态提供适当的用户反馈
总结
通过 Redux Toolkit 的 thunk 中间件和 createAsyncThunk
API,我们可以优雅地处理 Redux 中的异步逻辑。这种模式不仅适用于数据获取,也适用于任何需要与外部系统交互的场景。记住保持状态结构清晰,合理封装选择器,并为用户提供明确的加载和错误状态反馈。
在下一部分中,我们将探讨更高级的数据获取模式和使用 RTK Query 简化数据获取流程的方法。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考