React에서 setState를 사용하여 객체 업데이트


265

?로 객체의 속성을 업데이트하는 것이 가능 setState합니까?

다음과 같은 것 :

this.state = {
   jasper: { name: 'jasper', age: 28 },
}

나는 시도했다 :

this.setState({jasper.name: 'someOtherName'});

이:

this.setState({jasper: {name: 'someothername'}})

첫 번째 구문 오류가 발생하고 두 번째는 아무것도 수행하지 않습니다. 어떤 아이디어?


5
두 번째 코드는 효과가 있었지만 age내부 의 속성 을 잃어 버렸을 것 jasper입니다.
giorgim

답변:


577

상태 업데이트는 비동기 작업 이므로 여러 가지 방법이 있으므로 상태 객체를 업데이트하려면 업데이터 함수를와 함께 사용해야 합니다setState .

1- 가장 간단한 것 :

먼저 사본을 jasper만든 다음 다음과 같이 변경하십시오.

this.setState(prevState => {
  let jasper = Object.assign({}, prevState.jasper);  // creating copy of state variable jasper
  jasper.name = 'someothername';                     // update the name property, assign a new value                 
  return { jasper };                                 // return new object jasper object
})

사용하는 대신 Object.assign다음과 같이 작성할 수도 있습니다.

let jasper = { ...prevState.jasper };

2- 스프레드 연산자 사용 :

this.setState(prevState => ({
    jasper: {                   // object that we want to update
        ...prevState.jasper,    // keep all other key-value pairs
        name: 'something'       // update the value of specific key
    }
}))

참고 : Object.assignSpread Operator단지 생성 얕은 사본을 중첩 된 객체 또는 객체의 배열을 정의 그렇다면, 당신은 다른 접근 방식이 필요합니다.


중첩 된 상태 객체 업데이트 :

상태를 다음과 같이 정의했다고 가정하십시오.

this.state = {
  food: {
    sandwich: {
      capsicum: true,
      crackers: true,
      mayonnaise: true
    },
    pizza: {
      jalapeno: true,
      extraCheese: false
    }
  }
}

피자 개체의 extraCheese를 업데이트하려면 :

this.setState(prevState => ({
  food: {
    ...prevState.food,           // copy all other key-value pairs of food object
    pizza: {                     // specific object of food object
      ...prevState.food.pizza,   // copy all pizza key-value pairs
      extraCheese: true          // update value of specific key
    }
  }
}))

객체 배열 업데이트 :

할 일 앱이 있고 다음 형식으로 데이터를 관리한다고 가정합니다.

this.state = {
  todoItems: [
    {
      name: 'Learn React Basics',
      status: 'pending'
    }, {
      name: 'Check Codebase',
      status: 'pending'
    }
  ]
}

할 일 객체의 상태를 업데이트하려면 배열에서 맵을 실행하고 각 객체의 고유 한 값을 확인하십시오.의 경우 condition=true업데이트 된 값을 가진 새 객체를 반환하고 그렇지 않으면 동일한 객체를 반환하십시오.

let key = 2;
this.setState(prevState => ({

  todoItems: prevState.todoItems.map(
    el => el.key === key? { ...el, status: 'done' }: el
  )

}))

제안 : 객체에 고유 한 값이 없으면 배열 색인을 사용하십시오.


내가 지금 시도하고 있었던 방법은 지금 작동한다. .. 두 번째 방법 : S
JohnSnow

7
@JohnSnow 당신이 두 번째로 그것은 jasper개체 에서 다른 속성을 제거합니다 , console.log(jasper)당신은 하나의 키만 볼 수 있습니다 name, 나이는 없을 것입니다 :)
Mayank Shukla

1
@JohnSnow, 경우이 방법은 적절한입니다 예 jasper입니다 object수행이 아니라, 다른 더 나은 솔루션 : 가능있을 수 있습니다 최고의 있는지 여부
Mayank Shukla

6
Object.assign연산자 딥 카피 속성을 확산 시키지도 말고 여기에 언급하는 것이 좋습니다 . 이런 식으로 lodash deepCopy등과 같은 해결 방법을 사용해야합니다 .
Alex Vasilev

1
한판 승부 let { jasper } = this.state?
브라이언 르

37

가장 빠르고 읽기 쉬운 방법입니다.

this.setState({...this.state.jasper, name: 'someothername'});

this.state.jasper이미 이름 속성이 포함되어 있어도 새 이름 name: 'someothername'이 사용됩니다.


38
이 솔루션에는 한 가지 큰 단점이 있습니다. 상태 업데이트를 최적화하기 위해 React는 여러 업데이트를 그룹화 할 수 있습니다. 결과적으로 this.state.jasper반드시 최신 상태를 포함 할 필요는 없습니다. 로 표기법을 사용하는 것이 prevState좋습니다.
죄를 지었다

33

스프레드 연산자와 일부 ES6을 사용하십시오.

this.setState({
    jasper: {
          ...this.state.jasper,
          name: 'something'
    }
})

이것은 재스퍼를 업데이트하지만 다른 속성은 상태에서 제거됩니다.
iaq

11

이 솔루션을 사용했습니다.

다음과 같이 중첩 된 상태 인 경우 :

this.state = {
  formInputs:{
    friendName:{
      value:'',
      isValid:false,
      errorMsg:''
    },
    friendEmail:{
      value:'',
      isValid:false,
      errorMsg:''
    }
  }
}

현재 상태를 복사하고 변경된 값으로 재 할당하는 handleChange 함수를 선언 할 수 있습니다.

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

이벤트 리스너가있는 html입니다. 상태 객체에 사용 된 것과 동일한 이름 (이 경우 'friendName')을 사용해야합니다.

<input type="text" onChange={this.handleChange} " name="friendName" />

내가 대신를 사용했다를 제외하고 이것은 나를 위해 일한 :statusCopy.formInputs[inputName] = inputValue;
MikeyE

9

여기에 많은 답변이 있다는 것을 알고 있지만 setState 외부에서 새 객체의 복사본을 만든 다음 단순히 setState ({newObject})를 작성하는 사람이 아무도 없습니다. 깨끗하고 간결하며 신뢰할 수 있습니다. 따라서이 경우 :

const jasper = { ...this.state.jasper, name: 'someothername' }
this.setState(() => ({ jasper }))

또는 동적 속성 (매우 유용한 양식)

const jasper = { ...this.state.jasper, [VarRepresentingPropertyName]: 'new value' }
this.setState(() => ({ jasper }))


7

이것을 시도하십시오, 그것은 잘 작동합니다

this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));

4
상태 객체를 직접 변경하고 있습니다. 이 방법을 사용하려면 소스로 새 개체를 추가하십시오.Object.assign({}, this.state.jasper, {name:'someOtherName'})
Albizia

3

첫 번째 경우는 실제로 구문 오류입니다.

나머지 구성 요소를 볼 수 없기 때문에 왜 여기에 상태에 객체를 중첩시키는 지 알기가 어렵습니다. 구성 요소 상태에 개체를 중첩시키는 것은 좋지 않습니다. 초기 상태를 다음과 같이 설정하십시오.

this.state = {
  name: 'jasper',
  age: 28
}

이렇게하면 이름을 업데이트하려면 다음을 호출하면됩니다.

this.setState({
  name: 'Sean'
});

그것이 당신이 목표로하는 것을 달성 할 것입니까?

더 크고 복잡한 데이터 저장소의 경우 Redux와 같은 것을 사용합니다. 그러나 훨씬 더 발전했습니다.

구성 요소 상태의 일반적인 규칙은 구성 요소의 UI 상태 (예 : 활성, 타이머 등)를 관리하는 데만 사용하는 것입니다.

다음 참조를 확인하십시오.


1
나는 단지 예를 들어, 객체가 중첩되어야한다는 것을 사용했다. 나는 아마도 Redux를 사용해야하지만 React fundementals를 이해하려고 노력하고있다.
JohnSnow

2
그래, 나는 지금 Redux에서 멀리 떨어져있을 것입니다. 기초를 배우는 동안 데이터를 단순하게 유지하십시오. 그렇게하면 이상한 사건을 피하는 데 도움이됩니다. 👍
mccambridge

2

또 다른 옵션 : Jasper 객체 에서 변수를 정의한 다음 변수를 호출하십시오.

스프레드 연산자 : ES6

this.state = {  jasper: { name: 'jasper', age: 28 } } 

let foo = "something that needs to be saved into state" 

this.setState(prevState => ({
    jasper: {
        ...jasper.entity,
        foo
    }
})

2

간단하고 역동적 인 방법.

이것은 작업을 수행하지만 모든 ID를 부모로 설정해야 부모가 개체의 이름을 가리 키도록 id = "jasper"가되고 입력 요소의 이름이 개체 재스퍼 내부의 속성임을 나타내도록합니다. .

handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });

첫 번째 줄에 동의합니다. 이것이 상태의 객체 객체에 효과가 있었던 유일한 것입니다! 또한 데이터를 업데이트하는 데 걸린 위치를 정리했습니다. 지금까지 가장 간단하고 역동적 인 방법 ... 감사합니다 !!
미트

2

당신은 이것을 시도 할 수 있습니다 : ( : 입력 태그의 이름 === 객체의 필드)

<input name="myField" type="text" 
      value={this.state.myObject.myField} 
     onChange={this.handleChangeInpForm}>
</input>

-----------------------------------------------------------
handleChangeInpForm = (e) => {
   let newObject = this.state.myObject;
   newObject[e.target.name] = e.target.value;
   this.setState({
     myObject: newObject 
   })
}

스택 오버플로에 오신 것을 환영합니다. 이 코드는 질문에 대답 할 수 있지만,이 코드가 질문에 응답하는 이유 및 / 또는 방법에 대한 추가 컨텍스트를 제공하면 장기적인 가치가 향상됩니다. 답변 방법
Elletlar

2

이것은 immer immutabe 유틸리티를 사용하는 또 다른 솔루션으로 , 깊게 중첩 된 객체에 매우 적합하며 돌연변이에 신경 쓰지 않아야합니다.

this.setState(
    produce(draft => {
       draft.jasper.name = 'someothername
    })
)

1

또한 모든 "상태"개체를 복사하지 않으려는 경우 Alberto Piras 솔루션을 따르십시오.

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let jasperCopy = Object.assign({}, this.state.jasper);
    jasperCopy[inputName].name = inputValue;

    this.setState({jasper: jasperCopy});
  }

1

당신은 이것을 시도 할 수 있습니다 :

this.setState(prevState => {
   prevState = JSON.parse(JSON.stringify(this.state.jasper));
   prevState.name = 'someOtherName';
   return {jasper: prevState}
})

또는 다른 재산 :

this.setState(prevState => {
   prevState = JSON.parse(JSON.stringify(this.state.jasper));
   prevState.age = 'someOtherAge';
   return {jasper: prevState}
})

또는 handleChage 함수를 사용할 수 있습니다.

handleChage(event) {
   const {name, value} = event.target;
    this.setState(prevState => {
       prevState = JSON.parse(JSON.stringify(this.state.jasper));
       prevState[name] = value;
       return {jasper: prevState}
    })
}

HTML 코드 :

<input 
   type={"text"} 
   name={"name"} 
   value={this.state.jasper.name} 
   onChange={this.handleChange}
/>
<br/>
<input 
   type={"text"} 
   name={"age"} 
   value={this.state.jasper.age} 
   onChange={this.handleChange}
/>

이것은 JSON.stringify없이 작동합니다. this.setState (prevState => {prevState = this.state.document; prevState.ValidDate = event.target.value; prevState.ValidDateFormat = dayFormat; return {document : prevState}}); .. 문서가 상태 유형 객체 인 경우.
Oleg Borodko

1

비동기 및 대기를 사용하지 않고 이것을 사용하십시오 ...

funCall(){    
     this.setState({...this.state.jasper, name: 'someothername'});
}

Async And Await과 함께 사용하는 경우 이것을 사용하십시오 ...

async funCall(){
      await this.setState({...this.state.jasper, name: 'someothername'});
}

0

이 설정은 저에게 효과적이었습니다.

let newState = this.state.jasper;
newState.name = 'someOtherName';

this.setState({newState: newState});

console.log(this.state.jasper.name); //someOtherName
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.