React에서 중첩 상태 속성을 업데이트하는 방법


390

다음과 같이 중첩 속성을 사용하여 상태를 구성하려고합니다.

this.state = {
   someProperty: {
      flag:true
   }
}

하지만 이런 상태를 업데이트하면

this.setState({ someProperty.flag: false });

작동하지 않습니다. 어떻게 이것을 올바르게 할 수 있습니까?


4
작동하지 않는 것은 무엇을 의미합니까? 이것은 좋은 질문이 아닙니다. 무슨 일이 있었습니까? 오류가 있습니까? 무슨 오류?
대런 스위니


16
대답은 React에서 중첩 상태를 사용하지 않습니다 . 훌륭한 답변을 읽으십시오 .
Qwerty

4
대신 무엇을 사용해야합니까?
Jānis Elmeris

42
단순히 중첩 상태를 사용하지 않는 것은 오늘날 React가 얼마나 널리 사용되는지에 대한 용납 할 수없는 해답입니다. 이 상황이 다가올 것이며 개발자는 이에 대한 답변이 필요합니다.
serraosays

답변:


455

하기 위해 setState내가 setState를 중첩 업데이트를 처리하지 않습니다 생각하는 중첩 된 객체에 대해 당신이 접근 아래에 따를 수 있습니다.

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

아이디어는 더미 객체를 생성하여 작업을 수행 한 다음 구성 요소의 상태를 업데이트 된 객체로 교체하는 것입니다.

이제 스프레드 연산자는 객체의 하나의 레벨 중첩 복사본 만 만듭니다. 상태가 다음과 같이 고도로 중첩 된 경우 :

this.state = {
   someProperty: {
      someOtherProperty: {
          anotherProperty: {
             flag: true
          }
          ..
      }
      ...
   }
   ...
}

각 수준에서 스프레드 연산자를 사용하여 state를 설정할 수 있습니다.

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))

그러나 위의 구문은 상태가 점점 더 중첩 될 때마다 추악합니다. 따라서 사용하는 것이 좋습니다 immutability-helper 패키지를 사용하여 상태를 업데이트하는 .

로 상태를 업데이트하는 방법에 대한이 답변을 참조하십시오 immutability helper.


2
@Ohgodwhy는, 아니이 때문에 직접 상태를 액세스되지는 {... this.state.someProperty는}에 새로운 obejct을 retuns someProperty우리는 그 수정하는
하기 Shubham 카트리

4
이것은 나를 위해 작동하지 않았다 .. 나는 반응 버전 @ 15.6.1을 사용하고 있습니다
Rajiv

5
우리는 반드시 깊은 복제에 Lodash를 사용할 수 @Stophface하지만, 모든 사람은 setState를이 라이브러리를 포함 할 것
하기 Shubham 카트리

15
이것이 reactjs.org/docs/…를 위반하지 않습니까 ? 중첩 된 개체에 대한 두 가지 변경 사항이 일괄 처리 된 경우 마지막 변경 내용이 첫 번째 변경 내용을 덮어 씁니다. 가장 정확한 방법은 다음과 같습니다 this.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}}) . 조금 지루하지만 ...
olejorgenb

2
...prevState,마지막 예에서 당신 someProperty과 그 자녀들 만 필요하다고 생각하지 않습니다
Jemar Jones

140

한 줄에 쓰려면

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

12
setState 내에서 this.state에 직접 액세스하는 대신 setState 용 업데이트 프로그램을 사용하는 것이 좋습니다. reactjs.org/docs/react-component.html#setstate
Raghu Teja

6
나는 그 말을 믿습니다. this.state바로 읽지 말고 setState새로운 가치를 기대하십시오. this.state내에서 호출하는 것과 비교합니다 setState. 아니면 나에게 분명하지 않은 후자에도 문제가 있습니까?
trpt4him

2
으로 trpt4him는 말했다 링크는이 액세스하는 문제에 대한 회담을 준 this.state후를 setState. 게다가, 우리는 전달되지 않습니다 this.statesetState. 운영자 확산 특성. Object.assign ()과 동일합니다. github.com/tc39/proposal-object-rest-spread
요셉

3
@ RaghuTeja 아마도이 this.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });문제를 피할 수 있습니까?
Webwoman

완전성을 위해 useState 후크를 사용하여 동일한 결과를 얻는 방법 에 대한 답변 을 추가 했습니다 .
앤드류

90

때로는 직접 답변이 가장 좋은 답변이 아닙니다. :)

짧은 버전 :

이 코드

this.state = {
    someProperty: {
        flag: true
    }
}

다음과 같이 단순화해야합니다

this.state = {
    somePropertyFlag: true
}

긴 버전 :

현재 React에서 중첩 상태로 작업하고 싶지 않아야합니다. . React는 중첩 된 상태에서 작동하도록 설계되지 않았으므로 여기에서 제안 된 모든 솔루션은 해킹으로 보입니다. 그들은 프레임 워크를 사용하지 않고 싸워야합니다. 일부 속성을 그룹화하려는 의심스러운 목적을 위해 명확한 코드를 작성하지 않는 것이 좋습니다. 따라서 그들은 도전에 대한 답변으로 매우 흥미롭지 만 실제로는 쓸모가 없습니다.

다음과 같은 상태를 상상해 봅시다.

{
    parent: {
        child1: 'value 1',
        child2: 'value 2',
        ...
        child100: 'value 100'
    }
}

값을 변경하면 어떻게 child1됩니까? React는 얕은 비교를 사용하기 때문에 뷰를 다시 렌더링하지 않습니다.parent 하지 않으며 속성이 변경되지 않았 음을 알 수 있습니다. 상태 객체를 직접 변경하는 BTW는 일반적으로 나쁜 습관으로 간주됩니다.

그래서 당신은 전체를 다시 만들어야합니다 parent 개체 합니다. 그러나이 경우 우리는 다른 문제를 만날 것입니다. React는 모든 어린이가 자신의 가치를 바꾸고 다시 렌더링 할 것이라고 생각합니다. 물론 성능에는 좋지 않습니다.

복잡한 논리를 작성 하여이 문제를 해결할 수는 shouldComponentUpdate()있지만 여기서 멈추고 짧은 버전의 간단한 솔루션을 사용하는 것이 좋습니다.


4
중첩 된 상태가 완벽하게 사용되는 유스 케이스가 있다고 생각합니다. 예를 들어 키-값 쌍을 동적으로 추적하는 상태입니다. 이 상태에서 단지 하나의 항목에 대한 상태를 업데이트 할 수있는 방법 여기를 참조하십시오 : reactjs.org/docs/...
pors

1
기본적으로 순수 구성 요소에 대해 얕은 비교가 사용됩니다.
Basel Shishani

4
나는 당신의 영광을 위해 제단을 만들고 매일 아침기도하고 싶습니다. OBVIOUS 디자인 결정을 완벽하게 설명하는이 답변에 도달하는 데 3 일이 걸렸습니다. 모든 사람은 스프레드 연산자를 사용하거나 중첩 된 상태가 사람이 읽기 쉽도록 다른 해킹을 시도합니다.
Edeph

1
그렇다면 React를 사용하여 대화 형 트리 렌더링과 같은 작업을 수행하는 방법을 제안하는 방법은 무엇입니까? (예를 들어, 회사에는 세계 각지, 각기 다른 유형, 속성 및 위치에 따라 많은 센서가 있습니다 (80+ ), OF COURSE는 각 배포에 수천 달러의 비용이 들며 완전한 프로젝트이므로 계층 구조없이 관리 할 수 ​​없으므로 계층 구조로 구성됩니다. React에서 나무와 같은 것들을 나무처럼 모델링하지 않는 방법이 궁금합니다.
DanyAlejandro

10
React가 사소한 깊이의 재귀 구조로 저장된 것을 표현하기 위해 만들어지지 않은 것처럼 보입니다. 거의 모든 복잡한 응용 프로그램 (gmail, 파일 관리자, 모든 문서 관리 시스템 등)에 트리 뷰가 표시되므로 약간 실망 스럽습니다. 나는 이런 것들에 React를 사용했지만 항상 모든 사람들에게 안티 패턴을하고 있다고 말하고 솔루션이 모든 노드의 상태에서 나무의 딥 카피를 유지한다고 제안하는 React zealot (예, 80 카피)을 제안했습니다. React 규칙을 위반하지 않는 비 해킹 트리 뷰 구성 요소를보고 싶습니다.
DanyAlejandro 2019

61

기권

React의 중첩 상태가 잘못 설계되었습니다.

이 훌륭한 답변을 읽으십시오 .

 

이 답변 뒤에 추론 :

React의 setState는 기본 제공 편의 기능이지만 제한이 있음을 곧 깨닫게됩니다. 사용자 정의 속성을 사용하고 forceUpdate를 지능적으로 사용하면 훨씬 더 많은 것을 얻을 수 있습니다. 예 :

class MyClass extends React.Component {
    myState = someObject
    inputValue = 42
...

예를 들어 MobX는 상태를 완전히 도랑 화하고 사용자 지정 관찰 가능 속성을 사용합니다.
React 컴포넌트에서 상태 대신 Observables를 사용하십시오.

 


당신의 불행에 대한 답은 - 여기 예 참조

중첩 속성을 업데이트하는 또 다른 짧은 방법이 있습니다.

this.setState(state => {
  state.nested.flag = false
  state.another.deep.prop = true
  return state
})

한 줄에

 this.setState(state => (state.nested.flag = false, state))

참고 :이 여기 쉼표 연산자 ~ MDN은 행동에서 볼 여기 (샌드 박스) .

상태 참조를 변경하지는 않지만 비슷합니다.

this.state.nested.flag = false
this.forceUpdate()

이 컨텍스트 사이의 미묘한 차이 forceUpdatesetState 연결된 예를 참조.

물론 이것은 state읽기 전용이어야하기 때문에 몇 가지 핵심 원칙을 남용하고 있지만 이전 상태를 즉시 버리고 새로운 상태로 교체하기 때문에 완전히 괜찮습니다.

경고

상태 포함하는 구성 요소가 올바르게 업데이트되고 다시 렌더링 되지만 ( 이 gotcha 제외 ) 소품이 하위 항목으로 전파 되지 않습니다 (아래 Spymaster의 설명 참조). . 수행중인 작업을 알고있는 경우에만이 기술을 사용하십시오.

예를 들어, 업데이트되어 쉽게 전달 된 변경된 플랫 소품을 전달할 수 있습니다.

render(
  //some complex render with your nested state
  <ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)

complexNestedProp에 대한 참조가 변경되지 않았더라도 ( shouldComponentUpdate )

this.props.complexNestedProp === nextProps.complexNestedProp

구성 요소가 됩니다 호출 한 후의 경우 부모 구성 요소를 업데이트 할 때마다 다시 쓰게 this.setState또는 this.forceUpdate부모에 있습니다.

상태 변경의 영향

사용하여 중첩 된 상태를 다른 개체가 (고의 또는하지) 보유하고있는 서로 다른 (이상) 참조 수 있기 때문에 직접 상태를 돌연변이 것은 위험 상태 때 갱신을 반드시 알고하지 않을 수 있습니다 (예를 들어, 사용하는 경우 PureComponent또는 경우 shouldComponentUpdate반환에 구현 false) 또는 이다 아래 예와 같이 이전 데이터를 표시하기위한 것입니다.

과거 데이터를 렌더링해야하는 타임 라인을 상상해보십시오. 데이터를 변경하면 이전 항목도 변경되므로 예기치 않은 동작이 발생합니다.

상태 흐름 상태 흐름 중첩

어쨌든 여기 Nested PureChildClass에서 소품이 전파되지 않아서 다시 렌더링되지 않았다는 것을 알 수 있습니다 .


12
반응 상태를 어디에서나 변경해서는 안됩니다. state.nested 또는 state.another의 데이터를 사용하는 중첩 구성 요소가 있으면 다시 렌더링되거나 하위 요소가 아닙니다. 객체가 변경되지 않았기 때문에 React는 아무것도 변경되지 않았다고 생각합니다.
Zeragamba

@ SpyMaster356이 문제를 해결하기 위해 답변을 업데이트했습니다. 예를 들어 MobX state는 완전히 분리되고 사용자 지정 관찰 가능 속성을 사용 합니다. 리 액트 setState는 편의상 내장되어 있지만 곧 한계가 있음을 알게됩니다. 사용자 지정 속성을 사용하고 지능적으로 사용 forceUpdate하면 더 많은 것을 얻을 수 있습니다. React 컴포넌트에서 상태 대신 Observables를 사용하십시오.
Qwerty

또한 react-experiments.herokuapp.com/state-flow (위의 git에 링크) 예제를 추가했습니다
Qwerty

예를 들어 데이터베이스에서 중첩 속성이있는 객체를 상태로로드하면 어떻게됩니까? 이 경우 중첩 상태를 피하는 방법은 무엇입니까?
tobiv

3
@tobiv 페치시 데이터를 다른 구조로 변환하는 것이 좋지만 유스 케이스에 따라 다릅니다. 중첩 된 객체 또는 객체 배열을 일부 데이터의 컴팩트 한 단위로 생각하면 상태에있는 것이 좋습니다 . 내부 React diffing 알고리즘을 올바르게 트리거하려면 UI 스위치 또는 기타 관찰 가능한 데이터 (즉, 즉시보기를 변경해야하는 데이터)를 평평해야하므로 저장해야 할 때 문제가 발생합니다. 다른 중첩 객체의 변경 사항은 this.forceUpdate()specific을 쉽게 트리거 하거나 구현할 수 있습니다 shouldComponentUpdate.
Qwerty

21

ES2015를 사용하는 경우 Object.assign에 액세스 할 수 있습니다. 다음과 같이 사용하여 중첩 된 객체를 업데이트 할 수 있습니다.

this.setState({
  someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});

업데이트 된 속성을 기존 속성과 병합하고 반환 된 개체를 사용하여 상태를 업데이트합니다.

편집 : carkod가 지적한 것처럼 상태가 직접 변경되지 않도록 할당 함수에 대상으로 빈 객체를 추가했습니다.


12
그리고 나는 틀릴 수 있지만 ES2015 없이 React 사용하고 있다고 생각하지 않습니다 .
Madbreaks

16
const newState = Object.assign({}, this.state);
newState.property.nestedProperty = "new value";
this.setState(newState);

1
1) setState 내부의 지루한 확산을 피하고 2) setState 내부의 새로운 상태를 멋지게 배치하여 setState 내부의 직접 변경을 피하십시오. 마지막으로 최소한 3) 간단한 작업을 위해 라이브러리를 사용하지 않는 것
Webwoman

두 예는 동일하지 않습니다. property에 여러 개의 중첩 속성 이 포함되어 있으면 첫 번째 속성이 삭제되고 두 번째 속성은 삭제되지 않습니다. codesandbox.io/s/nameless-pine-42thu
Qwerty

쿼티, 당신은 그렇습니다, 노력에 감사드립니다. ES6 버전을 제거했습니다.
eyecandy.dev

간단하고 간단합니다!
Tony Sepia

나는 당신의 해결책을 사용했습니다. 내 상태 obj는 작고 정상적으로 작동했습니다. React가 변경된 상태에 대해서만 렌더링됩니까?
Kenji Noguchi

14

이를 돕기 위해 많은 라이브러리가 있습니다. 예를 들어, 불변성 헬퍼 사용 :

import update from 'immutability-helper';

const newState = update(this.state, {
  someProperty: {flag: {$set: false}},
};
this.setState(newState);

사용 lodash / FP 세트를 :

import {set} from 'lodash/fp';

const newState = set(["someProperty", "flag"], false, this.state);

사용 lodash / FP 병합 :

import {merge} from 'lodash/fp';

const newState = merge(this.state, {
  someProperty: {flag: false},
});

을 사용하는 경우 상태를 복제본으로 설정 lodash하려고 _.cloneDeep할 수 있습니다.
Yixing Liu

@YixingLiu : 사용하도록 답변을 업데이트 lodash/fp했으므로 돌연변이에 대해 걱정할 필요가 없습니다.
tokland

구문 외에 lodash / fp에서 선택 merge또는 set기능에 어떤 이점이 있습니까?
Toivo Säwén

좋은 대답 this.setState(newState)은 lodash / fp 메소드도 호출해야한다는 점 입니다. 또 다른 문제는 lodash .set(fp가 아닌)가 다른 순서의 인수를 사용하여 잠시 동안 나를 트립한다는 것입니다.
Toivo Säwén

7

우리는 이러한 종류의 문제를 처리하기 위해 Immer https://github.com/mweststrate/immer 를 사용 합니다.

구성 요소 중 하나에서이 코드를 교체했습니다.

this.setState(prevState => ({
   ...prevState,
        preferences: {
            ...prevState.preferences,
            [key]: newValue
        }
}));

이것으로

import produce from 'immer';

this.setState(produce(draft => {
    draft.preferences[key] = newValue;
}));

immer를 사용하면 상태를 "일반 객체"로 처리합니다. 마술은 프록시 객체로 무대 뒤에서 발생합니다.


6

다음은 추가 스레드, 라이브러리 또는 특수 함수가 필요하지 않은이 스레드에서 제공된 첫 번째 답변에 대한 변형입니다.

state = {
  someProperty: {
    flag: 'string'
  }
}

handleChange = (value) => {
  const newState = {...this.state.someProperty, flag: value}
  this.setState({ someProperty: newState })
}

특정 중첩 필드의 상태를 설정하기 위해 전체 개체를 설정했습니다. 변수를 만들고 ES2015 스프레드 연산자를 사용하여 newState현재 상태의 내용을 먼저 펼치면 됩니다. 그런 다음 값을 새 값으로 바꿨습니다 (현재 상태를 객체에 펼친 후에 설정했기 때문에 현재 상태의 필드가 무시됩니다). 그럼, 간단히의 상태를 설정 내에 객체입니다.this.state.flagflag: value flagsomePropertynewState


6

중첩은 실제로 구성 요소 상태를 처리하는 방법이 아니지만 단일 계층 중첩을 위해 쉬운 경우가 있습니다.

이런 상태에

state = {
 contact: {
  phone: '888-888-8888',
  email: 'test@test.com'
 }
 address: {
  street:''
 },
 occupation: {
 }
}

재사용 가능한 방법 ive는 다음과 같습니다.

handleChange = (obj) => e => {
  let x = this.state[obj];
  x[e.target.name] = e.target.value;
  this.setState({ [obj]: x });
};

그런 다음 주소를 지정하려는 각 중첩에 대해 obj 이름을 전달하십시오.

<TextField
 name="street"
 onChange={handleChange('address')}
 />

4

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

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

   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

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

확인했습니다. 이것은 이미 중첩 된 속성으로 이미 설정된 프로젝트를 처리하는 경우 효과적입니다.
metal_jacke1

4

상태의 사본을 작성하십시오.

let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))

이 객체를 변경하십시오.

someProperty.flag = "false"

이제 상태를 업데이트하십시오

this.setState({someProperty})

setState는 비동기입니다. 따라서 업데이트하는 동안 다른 사람 이이 함수를 호출하고 오래된 버전의 상태를 복사 할 수 있습니다.
아비브 Shabat

3

클래스 기반 React 구성 요소의 상태에 대해 질문했지만 useState 후크와 동일한 문제점이 있습니다. 더 나쁜 것은 : useState 후크는 부분 업데이트를 허용하지 않습니다. 따라서이 질문은 useState 후크가 도입되었을 때 매우 관련이되었습니다.

useState 후크가 사용되는보다 현대적인 시나리오에 문제가 있는지 확인하기 위해 다음 답변을 게시하기로 결정했습니다.

당신이 가지고 있다면 :

const [state, setState] = useState({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

현재를 복제하고 필요한 데이터 세그먼트를 패치하여 중첩 속성을 설정할 수 있습니다. 예를 들면 다음과 같습니다.

setState(current => { ...current, someProperty: { ...current.someProperty, flag: false } });

또는 Immer 라이브러리를 사용하여 객체의 복제 및 패치를 단순화 할 수 있습니다.

또는 Hookstate 라이브러리 (면책 조항 : 저자입니다)를 사용하여 복잡한 (로컬 및 글로벌) 상태 데이터를 간단히 관리하고 성능을 향상시킬 수 있습니다 (읽기 : 렌더링 최적화에 대해 걱정하지 마십시오).

import { useStateLink } from '@hookstate/core' 
const state = useStateLink({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

렌더링 할 필드를 가져옵니다.

state.nested.someProperty.nested.flag.get()
// or 
state.get().someProperty.flag

중첩 필드를 설정하십시오.

state.nested.someProperty.nested.flag.set(false)

다음은 상태가 트리와 같은 데이터 구조 에 깊게 / 재귀 적으로 중첩되어있는 Hookstate 예제 입니다.


2

아직 언급되지 않은 두 가지 옵션 :

  1. 깊이 중첩 된 상태 인 경우 루트에 앉도록 하위 오브젝트를 재구성 할 수 있는지 고려하십시오. 이를 통해 데이터를보다 쉽게 ​​업데이트 할 수 있습니다.
  2. Redux 문서에 나열된 불변 상태를 처리 할 수있는 편리한 라이브러리가 많이 있습니다 . 돌연변이 방식으로 코드를 작성할 수는 있지만 장면 뒤에서 필요한 복제를 처리하므로 Immer를 권장합니다. 또한 결과 객체를 고정시켜 나중에 실수로 변형 할 수 없습니다.

2

일반적인 사항을 만들기 위해 @ShubhamKhatri와 @Qwerty의 답변을 연구했습니다.

상태 객체

this.state = {
  name: '',
  grandParent: {
    parent1: {
      child: ''
    },
    parent2: {
      child: ''
    }
  }
};

입력 컨트롤

<input
  value={this.state.name}
  onChange={this.updateState}
  type="text"
  name="name"
/>
<input
  value={this.state.grandParent.parent1.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent1.child"
/>
<input
  value={this.state.grandParent.parent2.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent2.child"
/>

updateState 메소드

@State of @ShubhamKhatri의 답변으로 setState

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const oldstate = this.state;
  const newstate = { ...oldstate };
  let newStateLevel = newstate;
  let oldStateLevel = oldstate;

  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      newStateLevel[path[i]] = event.target.value;
    } else {
      newStateLevel[path[i]] = { ...oldStateLevel[path[i]] };
      oldStateLevel = oldStateLevel[path[i]];
      newStateLevel = newStateLevel[path[i]];
    }
  }
  this.setState(newstate);
}

@Statewer의 답변으로 setState

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const state = { ...this.state };
  let ref = state;
  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      ref[path[i]] = event.target.value;
    } else {
      ref = ref[path[i]];
    }
  }
  this.setState(state);
}

참고 : 위의 방법은 배열에서 작동하지 않습니다


2

구성 요소 상태의 전체 복사본을 만드는 데 대해 이미 우려한 점이 매우 심각합니다 . 그 말로, 나는 Immer를 강력하게 제안 할 것 입니다.

import produce from 'immer';

<Input
  value={this.state.form.username}
  onChange={e => produce(this.state, s => { s.form.username = e.target.value }) } />

프록시 객체를 영리하게 사용하여 임의로 깊은 상태 트리를 효율적으로 복사하기 때문에 React.PureComponent(즉 React의 얕은 상태 비교) 작동합니다 Immer. Immer는 또한 Immutability Helper와 같은 라이브러리에 비해 형식이 안전하며 Javascript 및 Typescript 사용자 모두에게 이상적입니다.


타이프 스크립트 유틸리티 기능

function setStateDeep<S>(comp: React.Component<any, S, any>, fn: (s: 
Draft<Readonly<S>>) => any) {
  comp.setState(produce(comp.state, s => { fn(s); }))
}

onChange={e => setStateDeep(this, s => s.form.username = e.target.value)}

1
stateUpdate = () => {
    let obj = this.state;
    if(this.props.v12_data.values.email) {
      obj.obj_v12.Customer.EmailAddress = this.props.v12_data.values.email
    }
    this.setState(obj)
}

1
나는 이것이 obj상태에 대한 참조 일 뿐이 므로 이것이 옳지 않다고 생각합니다 . 그래서 그것을 통해 당신은 실제 this.state객체를 변경하고 있습니다
Ciprian Tomoiagă

0

예를 들어 ID가 있고 이름이 있고 중첩 된 프로젝트의 상태를 유지하려는 경우 프로젝트 양식을 사용 하여이 기능이 작동한다는 것을 알았습니다.

return (
  <div>
      <h2>Project Details</h2>
      <form>
        <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
        <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
      </form> 
  </div>
)

알려주세요!


0

이런 식으로 충분할 수도 있습니다.

const isObject = (thing) => {
    if(thing && 
        typeof thing === 'object' &&
        typeof thing !== null
        && !(Array.isArray(thing))
    ){
        return true;
    }
    return false;
}

/*
  Call with an array containing the path to the property you want to access
  And the current component/redux state.

  For example if we want to update `hello` within the following obj
  const obj = {
     somePrimitive:false,
     someNestedObj:{
        hello:1
     }
  }

  we would do :
  //clone the object
  const cloned = clone(['someNestedObj','hello'],obj)
  //Set the new value
  cloned.someNestedObj.hello = 5;

*/
const clone = (arr, state) => {
    let clonedObj = {...state}
    const originalObj = clonedObj;
    arr.forEach(property => {
        if(!(property in clonedObj)){
            throw new Error('State missing property')
        }

        if(isObject(clonedObj[property])){
            clonedObj[property] = {...originalObj[property]};
            clonedObj = clonedObj[property];
        }
    })
    return originalObj;
}

const nestedObj = {
    someProperty:true,
    someNestedObj:{
        someOtherProperty:true
    }
}

const clonedObj = clone(['someProperty'], nestedObj);
console.log(clonedObj === nestedObj) //returns false
console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true

console.log()
const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
console.log(clonedObj2 === nestedObj) // returns false
console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
//returns true (doesn't attempt to clone because its primitive type)
console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty) 

0

나는 그것이 오래된 질문이라는 것을 알고 있지만 여전히 이것을 달성 한 방법을 공유하고 싶었습니다. 생성자의 상태를 다음과 같이 가정하십시오.

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      user: {
        email: ""
      },
      organization: {
        name: ""
      }
    };

    this.handleChange = this.handleChange.bind(this);
  }

handleChange기능은 다음과 같습니다

  handleChange(e) {
    const names = e.target.name.split(".");
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    this.setState((state) => {
      state[names[0]][names[1]] = value;
      return {[names[0]]: state[names[0]]};
    });
  }

입력 이름을 적절하게 지정하십시오.

<input
   type="text"
   name="user.email"
   onChange={this.handleChange}
   value={this.state.user.firstName}
   placeholder="Email Address"
/>

<input
   type="text"
   name="organization.name"
   onChange={this.handleChange}
   value={this.state.organization.name}
   placeholder="Organization Name"
/>

0

축소 검색으로 중첩 업데이트를 수행합니다 .

예:

상태에있는 중첩 변수 :

state = {
    coords: {
        x: 0,
        y: 0,
        z: 0
    }
}

함수:

handleChange = nestedAttr => event => {
  const { target: { value } } = event;
  const attrs = nestedAttr.split('.');

  let stateVar = this.state[attrs[0]];
  if(attrs.length>1)
    attrs.reduce((a,b,index,arr)=>{
      if(index==arr.length-1)
        a[b] = value;
      else if(a[b]!=null)
        return a[b]
      else
        return a;
    },stateVar);
  else
    stateVar = value;

  this.setState({[attrs[0]]: stateVar})
}

사용하다:

<input
value={this.state.coords.x}
onChange={this.handleTextChange('coords.x')}
/>

0

이것은 내 초기 상태입니다

    const initialStateInput = {
        cabeceraFamilia: {
            familia: '',
            direccion: '',
            telefonos: '',
            email: ''
        },
        motivoConsulta: '',
        fechaHora: '',
        corresponsables: [],
    }

후크 또는 상태 (클래스 구성 요소)로 바꿀 수 있습니다

const [infoAgendamiento, setInfoAgendamiento] = useState(initialStateInput);

handleChange의 메소드

const actualizarState = e => {
    const nameObjects = e.target.name.split('.');
    const newState = setStateNested(infoAgendamiento, nameObjects, e.target.value);
    setInfoAgendamiento({...newState});
};

중첩 된 상태로 상태를 설정하는 방법

const setStateNested = (state, nameObjects, value) => {
    let i = 0;
    let operativeState = state;
    if(nameObjects.length > 1){
        for (i = 0; i < nameObjects.length - 1; i++) {
            operativeState = operativeState[nameObjects[i]];
        }
    }
    operativeState[nameObjects[i]] = value;
    return state;
}

마지막으로 이것은 내가 사용하는 입력입니다.

<input type="text" className="form-control" name="cabeceraFamilia.direccion" placeholder="Dirección" defaultValue={infoAgendamiento.cabeceraFamilia.direccion} onChange={actualizarState} />

0

프로젝트에서 formik를 사용하는 경우이 물건을 처리하는 쉬운 방법이 있습니다. 다음은 formik를 사용하는 가장 쉬운 방법입니다.

먼저 formik initivalues ​​속성 또는 반응에서 초기 값을 설정하십시오. 상태

여기서 초기 값은 반응 상태로 정의됩니다.

   state = { 
     data: {
        fy: {
            active: "N"
        }
     }
   }

formik initiValues속성 내에서 formik 필드의 초기 값을 정의하십시오.

<Formik
 initialValues={this.state.data}
 onSubmit={(values, actions)=> {...your actions goes here}}
>
{({ isSubmitting }) => (
  <Form>
    <Field type="checkbox" name="fy.active" onChange={(e) => {
      const value = e.target.checked;
      if(value) setFieldValue('fy.active', 'Y')
      else setFieldValue('fy.active', 'N')
    }}/>
  </Form>
)}
</Formik>

formik 함수 string대신 업데이트 된 상태를 확인하기 위해 콘솔을 상태 를 설정하거나 반응 디버거 도구를 사용하여 formik 상태 값의 변경 사항을 확인하십시오.booleansetFieldValue


0

이 코드를 사용해보십시오 :

this.setState({ someProperty: {flag: false} });

그러나 이것은 someProperty위의 코드가 참조한 이후에 참조 된 객체에 존재하는 다른 모든 속성을 제거합니다. 속성 만 flag남습니다
Yashas

0

나는 책에서 다음을 보았다.

this.setState(state => state.someProperty.falg = false);

그러나 그것이 옳은지 잘 모르겠습니다 ..

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