如何通过字符串路径更新Immer draft的嵌套属性?
问题
你需要在immer的produce流程中,通过传入的字符串格式属性路径,修改深度嵌套的对象/数组属性值,示例场景如下:
const data = { colors: [{id: 1, name: 'red'}] } const path = "colors.0.name" const nextValue = "dark red" produce(data, (draft) => { // 在此处通过通用路径逻辑,将对应属性修改为dark red })
实现方法
完全可以在draft回调内完成这个需求,不需要依赖额外工具库,核心是在回调内部沿着路径逐层遍历draft节点,最终完成赋值即可,immer会自动追踪所有层级的修改。
直接写一个通用的路径赋值工具函数,在produce回调里调用就行:
import { produce } from 'immer' /** * 按字符串路径给immer draft设置属性值 * @param {object|array} draft immer生成的代理对象 * @param {string} path 点分隔的属性路径,数组下标直接传数字字符串即可 * @param {any} value 要设置的目标值 */ const setNestedValue = (draft, path, value) => { const keys = path.split('.') let node = draft // 遍历到目标属性的父节点 for (let i = 0; i < keys.length - 1; i++) { node = node[keys[i]] } // 给目标属性赋值 node[keys.at(-1)] = value } // 实际使用 const nextState = produce(data, (draft) => { setNestedValue(draft, path, nextValue) })
注意事项
- 上述实现默认传入的路径合法,即路径上的所有中间节点都真实存在。如果业务中存在路径断层的场景,可以在遍历过程中增加判断,按需自动创建缺失的对象/数组结构即可
- 不需要手动把路径里的数字字符串转成Number类型,JS中通过字符串下标访问数组元素和数字下标效果完全一致
- 路径遍历逻辑必须写在produce的回调内部执行,不要在回调外提前拿到路径对应节点的引用再修改,否则immer无法正确代理修改,会破坏不可变数据的生成逻辑
内容的提问来源于stack exchange,提问作者vuvu
相关产品推荐
相关产品推荐

