React Native+Redux中嵌套状态更新与添加的最优实现方法
嘿,这个场景我之前在处理Redux嵌套状态的时候也踩过坑!大量的空值判断和循环不仅代码冗余,还容易写错。结合React Native + Redux的技术栈,这里有几个我亲测好用的简化方案,能帮你把逻辑变得清爽很多:
方案一:用Redux Toolkit + Immer(最推荐)
Redux Toolkit(RTK)是官方现在主推的Redux开发工具,它默认集成了Immer——一个让你可以用"可变写法"实现不可变状态更新的库。完全不用再手动写展开运算符或者空值检查,代码逻辑会非常直观。
举个例子,假设你的初始状态是:
const initialState = { page1: { attrs: [ { attr1: { value: 10 } }, { attr2: { value: 20 } } ] } };
在RTK的createSlice里,你可以这么写处理属性更新的reducer:
import { createSlice } from '@reduxjs/toolkit'; const pageSlice = createSlice({ name: 'pages', initialState, reducers: { updateOrAddAttr: (state, action) => { const { pageKey, attrKey, valueToAdd } = action.payload; // 1. 处理页面不存在的情况:新增页面 if (!state[pageKey]) { state[pageKey] = { attrs: [] }; } // 2. 查找目标属性是否存在 const attrItem = state[pageKey].attrs.find(item => item[attrKey]); if (attrItem) { // 3. 属性已存在:累加value attrItem[attrKey].value += valueToAdd; } else { // 4. 属性不存在:新增属性 state[pageKey].attrs.push({ [attrKey]: { value: valueToAdd } }); } } } }); export const { updateOrAddAttr } = pageSlice.actions; export default pageSlice.reducer;
你看,这里完全不用手动处理不可变更新(比如...state、[...attrs]),Immer会帮你把这些"可变操作"转换成符合Redux要求的不可变更新,同时也省去了大量的空值判断(比如state[pageKey]?.attrs这种链式判断),逻辑和你直接操作普通对象一样清晰。
方案二:用Lodash的工具函数简化空值检查
如果你暂时不想迁移到RTK,或者习惯用Lodash,那可以用_.get和_.update这两个函数来简化嵌套属性的访问和更新:
import _ from 'lodash'; // 传统Redux reducer的写法 function pageReducer(state = initialState, action) { switch (action.type) { case 'UPDATE_OR_ADD_ATTR': { const { pageKey, attrKey, valueToAdd } = action.payload; // 先获取目标页面的attrs,不存在就返回空数组 const currentAttrs = _.get(state, `${pageKey}.attrs`, []); // 查找属性是否存在 const attrIndex = currentAttrs.findIndex(item => item[attrKey]); let newAttrs; if (attrIndex !== -1) { // 属性存在:累加value newAttrs = _.update([...currentAttrs], `${attrIndex}.${attrKey}.value`, val => val + valueToAdd); } else { // 属性不存在:新增 newAttrs = [...currentAttrs, { [attrKey]: { value: valueToAdd } }]; } // 返回新状态,页面不存在则自动创建 return _.set({ ...state }, `${pageKey}.attrs`, newAttrs); } default: return state; } }
_.get可以帮你安全地访问嵌套属性,不存在就返回默认值;_.set可以帮你直接设置嵌套属性,不管中间层级是否存在,省去了手动创建页面的判断逻辑。
方案三:手动封装工具函数(适合自定义场景)
如果你不想引入额外库,也可以自己封装一个简单的工具函数,来处理嵌套对象的安全访问和更新:
// 封装一个安全获取嵌套属性的函数 const getNested = (obj, path, defaultValue = null) => { return path.split('.').reduce((acc, key) => acc?.[key] ?? defaultValue, obj); }; // 封装一个安全设置嵌套属性的函数 const setNested = (obj, path, value) => { const newObj = { ...obj }; const keys = path.split('.'); const lastKey = keys.pop(); let current = newObj; keys.forEach(key => { if (!current[key]) current[key] = typeof keys[keys.indexOf(key)+1] === 'number' ? [] : {}; current = current[key]; }); current[lastKey] = value; return newObj; }; // 然后在reducer里使用这两个函数,逻辑和方案二类似,但不用依赖Lodash
总结
最推荐的还是Redux Toolkit + Immer的组合,不仅符合Redux的最佳实践,代码量最少,逻辑也最直观。如果是老项目,用Lodash的工具函数也能快速简化代码,避免大量的空值判断和循环。
内容的提问来源于stack exchange,提问作者Li Ho Yin

