Sync 대신 reactjs Async에서 setState가 사용되는 이유는 무엇입니까?


127

this.setState()모든 구성 요소의 반응 함수가 비동기 적이 거나 호출 된 함수가 완료된 후에 호출 된다는 것을 방금 발견 했습니다.

이제이 블로그를 검색하고 찾았습니다 ( setState () State Mutation Operation May Be Synchronous In ReactJS )

여기서 그는 setState상태 변경이 트리거 된 방법에 따라 async (스택이 비어있을 때 호출 됨) 또는 sync (호출되는 즉시 호출 됨) 임을 발견했습니다 .

이제이 두 가지는 소화하기 어렵습니다

  1. 블로그에서 setState함수는 함수 내부에서 호출 updateState되지만 함수 를 트리거 한 updateState것은 호출 된 함수가 알 수있는 것이 아닙니다.
  2. setStateJS가 단일 스레드 언어이고이 setState가 WebAPI 또는 서버 호출이 아니므로 JS 스레드에서만 수행해야하므로 비 동기화하는 이유는 무엇입니까? Re-Rendering으로 인해 모든 이벤트 리스너 및 항목이 중지되지 않도록이 작업을 수행하고 있거나 다른 디자인 문제가 있습니다.


1
나는 주위 기후의 비트를 설명하는 데 도움이 오늘 기사를 쓴 setState: medium.com/@agm1984/...을
agm1984

답변:


157

상태 값이 업데이트 된 후 함수를 호출 할 수 있습니다.

this.setState({foo: 'bar'}, () => { 
    // Do something here. 
});

또한 한 번에 업데이트 할 상태가 많은 경우 모두 동일한 내에서 그룹화합니다 setState.

대신에:

this.setState({foo: "one"}, () => {
    this.setState({bar: "two"});
});

다음과 같이하십시오.

this.setState({
    foo: "one",
    bar: "two"
});

17
나중에 사용할 수있는 콜백 함수가 있지만 문제는 아닙니다.
아누 프

12
바라건대 그것은이 질문을 어떻게 우연히 발견하는지 다른 사람을 도울 것입니다.
JoeTidee

2
나중에 나타나서 도움이 될 수 있습니다
아누 프

97

1) setState작업은 비동기 적이며 성능 향상을 위해 일괄 처리됩니다. 이것은의 문서에 설명되어 setState있습니다.

setState ()는 this.state를 즉시 변경하지 않지만 보류 상태 전환을 만듭니다. 이 메서드를 호출 한 후 this.state에 액세스하면 잠재적으로 기존 값을 반환 할 수 있습니다. setState에 대한 호출의 동기 작업이 보장되지 않으며 성능 향상을 위해 호출이 일괄 처리 될 수 있습니다.


2) JS가 단일 스레드 언어이고 이것은 setStateWebAPI 또는 서버 호출이 아니기 때문에 왜 setState를 비동기로 만들 까요?

이는 setState상태를 변경하고 다시 렌더링 하기 때문 입니다. 이것은 비용이 많이 드는 작업 일 수 있으며이를 동기식으로 만들면 브라우저가 응답하지 않을 수 있습니다.

따라서 setState 호출은 더 나은 UI 경험과 성능을 위해 비동기식이며 일괄 처리됩니다.


59
setState 호출 후 이벤트 순서를 확인해야하는 경우 콜백 함수를 전달할 수 있습니다. this.setState({ something: true }, () => console.log(this.state))
ianks

1
설명 해주신 @Sachin에게 감사드립니다. 그러나 나는 여전히 의심 스럽습니다. 블로그에서 설명하는 것처럼 동기식 일 수 있습니까?
Ajay Gaur

2
반응의 또 다른 어리석은 디자인 결정. 상태 업데이트를 동 기적으로 만들고 렌더링을 비동기로 만듭니다. 배치 렌더링을 할 수 있지만 경쟁 조건을 처리 할 필요없이 상태 변수처럼 원시적 인 것을 설정할 수 있기를 원합니다.
IG-DEV

기능을 비동기 또는 동기화로 설정하는 옵션을 허용하지 않는 이유는 무엇입니까? 즉 유용한 기능이 될 것입니다
랜달 코딩

분명히 나는 ​​반응 팀이 아니지만 상태 업데이트를 비동기로 만드는 한 가지 이유는 브라우저가 단일 스레드이기 때문입니다. 동기화 작업으로 인해 UI가 응답하지 않을 수 있으며 UI에 적합하지 않습니다.
Sachin

16

이 질문이 오래되었다는 것을 알고 있지만 저를 포함하여 오랫동안 많은 reactjs 사용자에게 많은 혼란을 가져 왔습니다. 최근에 Dan Abramov (react 팀의)는 왜의 특성 setState이 비동기 인지에 대한 훌륭한 설명을 작성했습니다 .

https://github.com/facebook/react/issues/11527#issuecomment-360199710

setState비동기식을 의미하며 Dan Abramov의 링크 된 설명에 그 이유가 몇 가지 있습니다. 이것은 항상 비동기 적이라는 것을 의미하지는 않습니다. 그것은 주로 동기 적이라는 것에 의존 할 수 없다는 것을 의미합니다 . ReactJS는 상태를 변경하는 시나리오에서 많은 변수를 고려하여 를 실제로 업데이트하고 구성 요소를 다시 렌더링해야하는 시기를 결정 합니다. 이를 보여주는 간단한 예 는 사용자 작업에 대한 반응으로 호출 하면state
setStatestate 즉시 업데이트 될 것이므로 (다시 말씀 드리지만, 믿을 수는 없지만) 사용자가 지연을 느끼지 않을 것입니다. ,하지만 전화하면setState ajax 호출 응답 또는 사용자에 의해 트리거되지 않은 다른 이벤트에 대한 반응으로 사용자가이 지연을 실제로 느끼지 않을 것이므로 약간의 지연으로 상태가 업데이트 될 수 있으며 대기하여 성능이 향상됩니다. 여러 상태 업데이트를 함께 일괄 처리하고 DOM을 더 적은 횟수로 다시 렌더링합니다.


당신은 어떤 answser도 올바른 것으로 표시하지 않았습니다. 사람들은 그것을 우회하는 방법을 게시하고 있습니다. 질문에 대한 대답이 아닙니다. 이 기사는 좋은 것 같습니다.
Anup

@Anup 대답은 'async'또는 'sync'보다 조금 더 복잡합니다. 항상 '비동기'로 처리되어야하지만 경우에 따라 '동기화'로 작동 할 수 있습니다. 나는 당신을 위해 약간의 빛을 비추 길 바랍니다.
gillyb

8

여기에 좋은 기사 https://github.com/vasanthk/react-bits/blob/master/patterns/27.passing-function-to-setState.md

// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3

Solution
this.setState((prevState, props) => ({
  count: prevState.count + props.increment
}));

또는 콜백 전달 this.setState ({.....},callback)

https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82 https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b



1

일부 구성 요소에서 카운터를 증가한다고 상상해보십시오.

  class SomeComponent extends Component{

    state = {
      updatedByDiv: '',
      updatedByBtn: '',
      counter: 0
    }

    divCountHandler = () => {
      this.setState({
        updatedByDiv: 'Div',
        counter: this.state.counter + 1
      });
      console.log('divCountHandler executed');
    }

    btnCountHandler = () => {
      this.setState({
        updatedByBtn: 'Button',
        counter: this.state.counter + 1
      });
      console.log('btnCountHandler executed');
    }
    ...
    ...
    render(){
      return (
        ...
        // a parent div
        <div onClick={this.divCountHandler}>
          // a child button
          <button onClick={this.btnCountHandler}>Increment Count</button>
        </div>
        ...
      )
    }
  }

부모 및 자식 구성 요소 모두에 연결된 개수 처리기가 있습니다. 이것은 의도적으로 수행되므로 동일한 클릭 이벤트 버블 링 컨텍스트 내에서 setState ()를 두 번 실행할 수 있지만 두 개의 다른 핸들러 내에서 실행할 수 있습니다.

우리가 상상할 수 있듯이, 버블 링 단계 동안 이벤트 버블이 타겟에서 가장 바깥 쪽 컨테이너로 버블 링되기 때문에 버튼에 대한 단일 클릭 이벤트가 이제이 두 핸들러를 모두 트리거합니다.

따라서 btnCountHandler ()가 먼저 실행되고 카운트가 1로 증가한 다음 divCountHandler ()가 실행되고 카운트가 2로 증가합니다.

그러나 React Developer 도구에서 검사 할 수 있으므로 개수는 1로만 증가합니다.

이것은 그 반응을 증명합니다.

  • 모든 setState 호출을 큐에 넣습니다.

  • 컨텍스트에서 마지막 메서드 (이 경우 divCountHandler)를 실행 한 후이 큐로 돌아옵니다.

  • 동일한 컨텍스트에서 여러 setState 호출 내에서 발생하는 모든 객체 변형 (예 : 단일 이벤트 단계 내의 모든 메서드 호출은 동일한 컨텍스트)을 하나의 단일 객체 변형 구문으로 병합합니다 (이것이 상태 속성을 독립적으로 업데이트 할 수있는 이유이기 때문에 합리적입니다. 처음에는 setState ()에서)

  • 여러 setState () 호출로 인해 다시 렌더링되는 것을 방지하기 위해 하나의 setState ()에 전달합니다 (이것은 일괄 처리에 대한 매우 원시적 인 설명입니다).

반응에 의해 실행되는 결과 코드 :

this.setState({
  updatedByDiv: 'Div',
  updatedByBtn: 'Button',
  counter: this.state.counter + 1
})

이 동작을 중지하기 위해 setState 메서드에 대한 인수로 개체를 전달하는 대신 콜백이 전달됩니다.

    divCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByDiv: 'Div',
              counter: prevState.counter + 1
            };
          });
          console.log('divCountHandler executed');
        }

    btnCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByBtn: 'Button',
              counter: prevState.counter + 1
            };
          });
      console.log('btnCountHandler executed');
    }

마지막 메소드가 실행을 마치고 react가 setState 대기열을 처리하기 위해 반환되면 대기열에있는 각 setState에 대한 콜백을 호출하여 이전 구성 요소 상태를 전달합니다.

이러한 방식으로 반응하면 대기열의 마지막 콜백이 이전의 모든 콜백이 손을 댄 상태를 업데이트 할 수 있습니다.


0

예, setState ()는 비동기입니다.

링크에서 : https://reactjs.org/docs/react-component.html#setstate

  • React는 상태 변경이 즉시 적용된다는 것을 보장하지 않습니다.
  • setState ()는 항상 구성 요소를 즉시 업데이트하지는 않습니다.
  • setState ()를 구성 요소를 업데이트하기위한 즉각적인 명령이 아니라 요청으로 생각하십시오.

그들은
링크에서 생각하기 때문에 : https://github.com/facebook/react/issues/11527#issuecomment-360199710

... 동 기적으로 다시 렌더링하는 setState ()가 많은 경우에 비효율적이라는 데 동의합니다.

비동기식 setState ()는 시작하고 불행히도 경험 한 사람들에게 삶을 매우 어렵게 만듭니다
.-예기치 않은 렌더링 문제 : 렌더링 지연 또는 렌더링 없음 (프로그램 논리 기반)
-매개 변수 전달은
다른 문제 중에서도 큰 문제입니다.

아래 예가 도움이되었습니다.

// call doMyTask1 - here we set state
// then after state is updated...
//     call to doMyTask2 to proceed further in program

constructor(props) {
    // ..

    // This binding is necessary to make `this` work in the callback
    this.doMyTask1 = this.doMyTask1.bind(this);
    this.doMyTask2 = this.doMyTask2.bind(this);
}

function doMyTask1(myparam1) {
    // ..

    this.setState(
        {
            mystate1: 'myvalue1',
            mystate2: 'myvalue2'
            // ...
        },    
        () => {
            this.doMyTask2(myparam1); 
        }
    );
}

function doMyTask2(myparam2) {
    // ..
}

도움이되기를 바랍니다.

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