React中使用useState钩子实现深层嵌套对象值修改与字段增删
React深层嵌套状态更新实现方案
原生useState实现(无第三方依赖)
React状态更新的核心原则是必须返回全新的状态对象,不能直接修改原状态,否则不会触发组件重渲染。所有层级的更新都需要逐层拷贝被修改路径上的所有对象/数组。
假设你的状态定义如下:
const [state, setState] = useState(/* 你的初始嵌套对象 */)
以下是各场景的实现示例:
1. 更新/新增/删除key1.key2
// 直接替换整个key2数组 setState(prev => ({ ...prev, key1: { ...prev.key1, key2: 新的key2数组 } })) // 新增元素到key2末尾 setState(prev => ({ ...prev, key1: { ...prev.key1, key2: [...prev.key1.key2, 新增的元素对象] } })) // 删除key2中指定索引的元素 const delIndex = 1 // 要删除的索引 setState(prev => ({ ...prev, key1: { ...prev.key1, key2: prev.key1.key2.filter((_, idx) => idx !== delIndex) } }))
2. 更新/新增/删除key1.key2[index].field1
const key2Index = 0 // key2数组的目标索引 const targetValue = '新的值' // 更新field1 setState(prev => { const newKey2 = [...prev.key1.key2] newKey2[key2Index] = { ...newKey2[key2Index], field1: targetValue // 新增键直接在这里加,比如 newField: 'xxx' } // 删除键用解构排除,比如: // const { field1, ...restItem } = newKey2[key2Index] // newKey2[key2Index] = restItem return { ...prev, key1: { ...prev.key1, key2: newKey2 } } })
3. 更新/新增/删除key1.key2[index].field2[index]
const key2Index = 0 const field2Index = 1 const targetValue = '新的值' setState(prev => { const newKey2 = [...prev.key1.key2] const key2Item = { ...newKey2[key2Index] } key2Item.field2 = [...key2Item.field2] // 更新指定位置的值 key2Item.field2[field2Index] = targetValue // 新增元素用push逻辑:key2Item.field2.push('新增值') // 删除元素用filter:key2Item.field2 = key2Item.field2.filter((_, idx) => idx !== field2Index) newKey2[key2Index] = key2Item return { ...prev, key1: { ...prev.key1, key2: newKey2 } } })
4. 更新key1.key2[index].field3[index].ff2[index]
const key2Index = 0 const field3Index = 0 const ff2Index = 0 const targetValue = '新的值' setState(prev => { const newKey2 = [...prev.key1.key2] const key2Item = { ...newKey2[key2Index] } key2Item.field3 = [...key2Item.field3] const field3Item = { ...key2Item.field3[field3Index] } field3Item.ff2 = [...field3Item.ff2] field3Item.ff2[ff2Index] = targetValue key2Item.field3[field3Index] = field3Item newKey2[key2Index] = key2Item return { ...prev, key1: { ...prev.key1, key2: newKey2 } } })
5. 更新最深层key1.key2[index].field3[index].ff3[index][index].key
const key2Index = 0 const field3Index = 0 const ff3FirstIndex = 0 const ff3SecondIndex = 1 const targetKey = 'f2' const targetValue = 3 setState(prev => { const newKey2 = [...prev.key1.key2] const key2Item = { ...newKey2[key2Index] } key2Item.field3 = [...key2Item.field3] const field3Item = { ...key2Item.field3[field3Index] } field3Item.ff3 = [...field3Item.ff3] const ff3FirstArr = [...field3Item.ff3[ff3FirstIndex]] const ff3Item = { ...ff3FirstArr[ff3SecondIndex] } ff3Item[targetKey] = targetValue ff3FirstArr[ff3SecondIndex] = ff3Item field3Item.ff3[ff3FirstIndex] = ff3FirstArr key2Item.field3[field3Index] = field3Item newKey2[key2Index] = key2Item return { ...prev, key1: { ...prev.key1, key2: newKey2 } } })
简化方案:使用Immer
原生写法层级越深越容易漏拷贝导致状态不更新,推荐使用Immer库简化不可变更新逻辑,不需要手动逐层拷贝,直接修改 draft 对象即可,Immer会自动生成全新的不可变状态。
使用示例
- 安装Immer和use-immer后定义状态:
import { useImmer } from 'use-immer' const [state, updateState] = useImmer(/* 初始状态 */)
- 任意层级的更新都可以直接操作:
// 更新最深层的值 updateState(draft => { draft.key1.key2[0].field3[0].ff3[0][1].f2 = 3 }) // 给field2新增元素 updateState(draft => { draft.key1.key2[0].field2.push('新增值') }) // 删除指定键 updateState(draft => { delete draft.key1.key2[0].field1 })
内容的提问来源于stack exchange,提问作者Saikat Dey
相关产品推荐
相关产品推荐

