如何使用Redux Toolkit在一个slice的reducer中访问其他slice的state
问题原因
出现崩溃本质是违反了Redux的核心设计约束:
- Redux要求所有slice的reducer必须是纯函数,仅依赖传入的当前slice state、action对象两个入参计算新状态,执行过程中不能读取外部可变值
- reducer执行阶段正处于全量store状态更新的中间过程,此时全局store还未生成本次更新后的稳定状态,调用
getState()要么拿到过期旧值,要么触发更新流程重入直接导致崩溃 - 直接在slice reducer中读取其他slice状态,还会造成slice之间强耦合,后续代码拆分、单元测试都会遇到问题
推荐实现方案
1. 触发action时提前传入需要的跨slice状态
这是最符合Redux设计规范的实现方式:在调用dispatch的位置(通常是业务组件),通过selector拿到需要的其他slice状态,作为action payload的一部分传入reducer,reducer直接从payload取值即可,不需要感知其他slice的存在。
示例代码:
// 组件侧 import { useDispatch, useSelector } from 'react-redux' import { updateArticle } from './articleSlice' function ArticleEditor() { const dispatch = useDispatch() // 提前拿到user slice的状态 const currentUser = useSelector(state => state.user) const handleSave = (content) => { // 把需要的跨slice值作为payload传入 dispatch(updateArticle({ content, operatorId: currentUser.id })) } } // articleSlice的reducer中直接取payload值,不需要访问其他slice const articleSlice = createSlice({ name: 'article', initialState: {}, reducers: { updateArticle: (state, action) => { const { content, operatorId } = action.payload state.content = content state.lastOperator = operatorId state.updateTime = Date.now() } } })
2. 用thunk中间件统一获取跨slice状态
如果逻辑比较复杂、多个地方需要触发同一个带跨slice状态的action,可以把逻辑封装到thunk函数中:thunk函数执行时,全量store状态是已经提交的稳定状态,可以安全调用getState()拿到所有slice的最新值,处理完成后再把计算好的参数传给普通action,交给reducer做纯状态更新。
示例代码:
// 定义thunk逻辑 export const saveArticle = (content) => async (dispatch, getState) => { // 安全获取全量状态 const rootState = getState() const currentUser = rootState.user const articleConfig = rootState.config.article // 可以顺便处理接口请求等副作用 const res = await fetch('/api/save-article', { method: 'POST', body: JSON.stringify({ content, userId: currentUser.id, allowComment: articleConfig.defaultAllowComment }) }) // 状态更新还是交给纯reducer dispatch(updateArticle({ content, lastOperator: currentUser.id, id: res.data.id })) }
3. 抽离公共状态逻辑
如果多个slice都需要依赖同一份状态做更新,不要在各个slice里互相读取状态,可以把这部分公共逻辑抽成独立的公共reducer函数,或者在根reducer层统一处理跨slice的状态组合,保证每个slice的reducer只处理自己负责的状态片段。
禁止做法
不要为了省事直接在slice文件中import全局store实例,调用store.getState()取值:这种写法会造成slice和store实例强耦合,引发循环依赖问题,单元测试时无法独立测试slice逻辑,还会拿到非预期的旧状态导致业务bug。
内容的提问来源于stack exchange,提问作者Neha Gupta
相关产品推荐
相关产品推荐

