在嵌套对象中,在React with Hooks中更新状态的正确方法是什么?

export Example = () => {
  const [exampleState, setExampleState] = useState(
  {masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b"
           fieldTwoTwo: "c"
           }
        }
   })

如何使用setExampleState将exampleState更新为a(附加字段)?

const a = {
masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b",
           fieldTwoTwo: "c"
           }
        },
  masterField2: {
        fieldOne: "c",
        fieldTwo: {
           fieldTwoOne: "d",
           fieldTwoTwo: "e"
           }
        },
   }
}

b(改变值)?

const b = {masterField: {
        fieldOne: "e",
        fieldTwo: {
           fieldTwoOne: "f"
           fieldTwoTwo: "g"
           }
        }
   })

当前回答

我迟到了。:)

@aseferov回答在意图是重新进入整个对象结构时非常有效。然而,如果目标/目标是更新Object中的特定字段值,我认为下面的方法更好。

情境:

const [infoData, setInfoData] = useState({
    major: {
      name: "John Doe",
      age: "24",
      sex: "M",
    },

    minor:{
      id: 4,
      collegeRegion: "south",

    }

  });

更新特定的记录需要回调到之前的状态prevState

在这里:

setInfoData((prevState) => ({
      ...prevState,
      major: {
        ...prevState.major,
        name: "Tan Long",
      }
    }));

也许

setInfoData((prevState) => ({
      ...prevState,
      major: {
        ...prevState.major,
        name: "Tan Long",
      },
      minor: {
        ...prevState.minor,
        collegeRegion: "northEast"

    }));

我希望这对试图解决类似问题的人有所帮助。

其他回答

function App() {

  const [todos, setTodos] = useState([
    { id: 1, title: "Selectus aut autem", completed: false },
    { id: 2, title: "Luis ut nam facilis et officia qui", completed: false },
    { id: 3, title: "Fugiat veniam minus", completed: false },
    { id: 4, title: "Aet porro tempora", completed: true },
    { id: 5, title: "Laboriosam mollitia et enim quasi", completed: false }
  ]);

  const changeInput = (e) => {todos.map(items => items.id === parseInt(e.target.value) && (items.completed = e.target.checked));
 setTodos([...todos], todos);}
  return (
    <div className="container">
      {todos.map(items => {
        return (
          <div key={items.id}>
            <label>
<input type="checkbox" 
onChange={changeInput} 
value={items.id} 
checked={items.completed} />&nbsp; {items.title}</label>
          </div>
        )
      })}
    </div>
  );
}

我认为更优雅的解决方案是创建更新后的状态对象,同时保留以前的state值。需要更新的Object属性可以以这样的数组形式提供

import React,{useState, useEffect} from 'react'
export default function Home2(props) {
    const [x, setX] = useState({name : '',add : {full : '', pin : '', d : { v : '' }}})
    const handleClick = (e, type)=>{
        let obj = {}
        if(type.length > 1){
            var z = {}
            var z2 = x[type[0]]
        
        type.forEach((val, idx)=>{
            if(idx === type.length - 1){
                z[val] = e.target.value
            }
            else if(idx > 0){
                Object.assign(z , z2) /*{...z2 , [val]:{} }*/
                z[val] = {}
                z = z[val]
                z2 = z2[val]
            }else{
                z = {...z2}
                obj = z
            }
        })
    }else obj = e.target.value
    setX( { ...x ,   [type[0]] : obj  } )
    
}
return (
    <div>
        <input value = {x.name} onChange={e=>handleClick(e,["name"])}/>
        <input value = {x.add.full} onChange={e=>handleClick(e,["add","full"])}  />
        <input value = {x.add.pin} onChange={e=>handleClick(e,["add","pin"])}  /><br/>
        <input value = {x.add.d.v} onChange={e=>handleClick(e,["add","d","v"])}  /><br/>
        {x.name} <br/>
        {x.add.full} <br/>
        {x.add.pin} <br/>
        {x.add.d.v}
    </div>
)
}

谢谢Philip,这帮助了我-我的用例是我有一个有很多输入字段的表单,所以我保持初始状态为对象,我不能更新对象状态。上面的帖子帮助了我:)

const [projectGroupDetails, setProjectGroupDetails] = useState({
    "projectGroupId": "",
    "projectGroup": "DDD",
    "project-id": "",
    "appd-ui": "",
    "appd-node": ""    
});

const inputGroupChangeHandler = (event) => {
    setProjectGroupDetails((prevState) => ({
       ...prevState,
       [event.target.id]: event.target.value
    }));
}

<Input 
    id="projectGroupId" 
    labelText="Project Group Id" 
    value={projectGroupDetails.projectGroupId} 
    onChange={inputGroupChangeHandler} 
/>


您必须使用Rest参数和扩展语法(https://javascript.info/rest-parameters-spread),并设置一个以preState作为setState参数的函数。

不起作用(功能缺失)

[state, setState] = useState({})
const key = 'foo';
const value = 'bar';
setState({
  ...state,
  [key]: value
});

确实工作!

[state, setState] = useState({})
const key = 'foo';
const value = 'bar';
setState(prevState => ({
  ...prevState,
  [key]: value
}));

我已经给出了两个追加,整个对象更新,具体的关键更新的解决方案的例子

追加和修改都可以通过一个简单的步骤来完成。我认为这是更稳定和安全的,没有不可变或可变的依赖。

这就是追加新对象的方法

setExampleState(prevState => ({
    ...prevState,
    masterField2: {
        fieldOne: "c",
        fieldTwo: {
            fieldTwoOne: "d",
            fieldTwoTwo: "e"
        }
    },
}))

假设您想再次修改masterField2对象。可能有两种情况。您想要更新整个对象或更新对象的特定键。

更新整个对象-这里masterField2键的整个值将被更新。

setExampleState(prevState => ({
    ...prevState,
    masterField2: {
        fieldOne: "c",
        fieldTwo: {
            fieldTwoOne: "d",
            fieldTwoTwo: "e"
        }
    },
}))

但是如果你只想改变masterField2对象中的fieldTwoOne键呢?你可以这样做。

let oldMasterField2 = exampleState.masterField2
oldMasterField2.fieldTwo.fieldTwoOne = 'changed';
setExampleState(prevState => ({
    ...prevState,
    masterField2: oldMasterField2
}))