如何构建包含重复嵌套切片的Redux + Redux Toolkit store
核心实现思路
你不需要修改原有三个子切片的内部逻辑,只需要把它们的reducer和初始状态导出,在blogsSlice中通过extraReducers的匹配器代理子切片的action,将对应博客下的子状态传入子reducer处理即可,具体实现如下:
1. 改造原有子切片,导出初始状态与reducer
把原有的postsSlice、commentsSlice、usersSlice的初始状态和reducer单独导出,不需要再注册到根reducer中,示例代码:
// postsSlice.js 示例,comments和users切片同理改造 import { createSlice } from '@reduxjs/toolkit' // 单独导出初始状态 export const initialPostsState = { byId: {}, allIds: [] } const postsSlice = createSlice({ name: 'posts', initialState: initialPostsState, reducers: { addPost: (state, action) => { // 保留你原有逻辑不变 const newPost = action.payload state.byId[newPost.id] = newPost state.allIds.push(newPost.id) }, // 其他原有reducer逻辑保留 } }) export const { addPost } = postsSlice.actions // 单独导出reducer export const postsReducer = postsSlice.reducer
2. 定义blogsSlice
import { createSlice, createAction } from '@reduxjs/toolkit' import { postsReducer, initialPostsState } from './postsSlice' import { commentsReducer, initialCommentsState } from './commentsSlice' import { usersReducer, initialUsersState } from './usersSlice' // 定义新增博客的action export const addBlog = createAction('blogs/addBlog', (blogId) => { return { payload: { blogId } } }) const blogsSlice = createSlice({ name: 'blogs', initialState: { byId: {}, allIds: [] }, extraReducers: (builder) => { // 新增博客的逻辑,初始化对应博客下的三个子状态 builder.addCase(addBlog, (state, action) => { const { blogId } = action.payload if (!state.byId[blogId]) { state.byId[blogId] = { posts: initialPostsState, comments: initialCommentsState, users: initialUsersState } state.allIds.push(blogId) } }) // 匹配所有子切片的action,代理到对应博客的子状态处理 .addMatcher( (action) => action.type.startsWith('posts/') || action.type.startsWith('comments/') || action.type.startsWith('users/'), (state, action) => { // 约定所有子操作的payload必须携带blogId参数,指定要操作的博客 const { blogId } = action.payload const targetBlog = state.byId[blogId] if (!targetBlog) return // 调用对应子reducer处理子状态 if (action.type.startsWith('posts/')) { targetBlog.posts = postsReducer(targetBlog.posts, action) } else if (action.type.startsWith('comments/')) { targetBlog.comments = commentsReducer(targetBlog.comments, action) } else if (action.type.startsWith('users/')) { targetBlog.users = usersReducer(targetBlog.users, action) } } ) } }) export const blogsReducer = blogsSlice.reducer
3. 调整使用方式
- 调用子切片action时,payload需要新增
blogId字段指定操作的博客:
// 给blog1新增帖子,原有post字段不变,仅新增blogId参数 dispatch(addPost({ blogId: 'blog1', id: 'post1', author: 'user1', body: '测试内容', comments: [] }))
- 读取状态时按路径访问即可:
state.blogs.byId[blogId].posts
内容的提问来源于stack exchange,提问作者AlonF
相关产品推荐
相关产品推荐

