react setState 메소드를 호출해도 상태가 즉시 변경되지 않는 이유는 무엇입니까?


326

양식 섹션을 읽고 있습니다.설명서를 작성 하고이 코드를 onChange사용 하여 사용법 을 보여 줍니다 ( JSBIN ).

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

<input/>브라우저 에서 값을 업데이트하면 콜백 console.log내부 의 두 번째 가 첫 번째 handleChange와 동일 value하게 인쇄 됩니다. 콜백 범위에서 console.log결과를 볼 수없는 이유는 무엇 입니까?this.setState({value: event.target.value})handleChange


답변:


615

React의 문서에서 :

setState()즉시 변경하지 않고 this.state보류 상태 전환을 만듭니다. this.state이 메소드를 호출 한 후 액세스 하면 기존 값이 리턴 될 수 있습니다. 동시 호출 호출을 보장하지 않으며 setState성능 향상을 위해 호출을 일괄 처리 할 수 ​​있습니다.

상태 변경 후 함수를 실행하려면 콜백으로 전달하십시오.

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});

좋은 대답입니다. 내가해야 할 관찰은 valueLink를 사용하는 데주의를 기울입니다. 입력을 포맷 / 마스킹 할 필요가없는 경우에 효과적입니다.
Dherik December

42
당신은 또한 체크 아웃 할 수 있습니다 componentDidUpdate. 상태가 변경된 후에 호출됩니다.
Keysox

1
빠른 질문이라면, 일단 setState에 콜백으로 필요한 함수를 전달하면 render ()가 호출되기 전에 func이 먼저 실행될 것으로 기대했습니다. 그러나 순서는 setState ()-> render ()-> setStates 'callback ()입니다. 이것이 정상입니까? 콜백에서하는 작업을 기반으로 렌더를 제어하려면 어떻게해야합니까? shouldComponentUpdate ?
semuzaboi 2016 년

2
shouldComponentUpdate다르게 지정된 동작이 없으면 구성 요소의 상태를 변경하면 항상 다시 렌더링이 트리거 됩니다. setState다시 렌더링하기 전에 전달 하려는 콜백에서 정확히 무엇을하려고 합니까?
Michael Parker

4
...왜? 누군가 이것을 정당화 할 수 있습니까?
JackHasaKeyboard

49

React 문서에서 언급했듯이 setState동기식으로 발사되는 것을 보장하지 않으므로 console.log업데이트하기 전에 상태를 반환 할 수 있습니다.

Michael Parker는에서 콜백을 전달한다고 언급했습니다 setState. 상태 변경 후 로직을 처리하는 다른 방법은 componentDidUpdate라이프 사이클 방법을 사용하는 것입니다. 라이프 사이클 방법은 React 문서에서 권장되는 방법입니다.

일반적으로 그러한 논리에 componentDidUpdate ()를 사용하는 것이 좋습니다.

이것은 연속적으로 setState발생 했을 때 특히 유용하며 , 모든 상태 변경 후에 동일한 기능을 실행하려고합니다. 각에 콜백을 추가하는 대신 필요한 경우 특정 논리를 사용 setState하여 함수를에 포함시킬 수 componentDidUpdate있습니다.

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}

16

ES7 async / await를 사용해보십시오. 예를 들어 예를 사용하면 다음과 같습니다.

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}

답변이 다른 고품질 답변과 어떻게 다릅니 까?
tod

9
다른 대답은 setState ()에서 콜백을 사용하는 것과 관련이 있습니다. 콜백 사용 사례가 적용되지 않는 사람들을 위해 여기에 넣었다고 생각했습니다. 예를 들어,이 문제에 직접 직면했을 때 유스 케이스에는 설정 직후 업데이트 된 상태의 스위치 케이스가 포함되었습니다. 따라서 콜백을 사용하는 것보다 async / await를 사용하는 것이 좋습니다.
kurokiiru

상태를 업데이트하고 업데이트를 기다릴 때 항상 대기를 사용하면 성능에 영향을 미칩니 까? 그리고 여러 await setStates를 체인 아래에 하나씩 놓으면 각 setState 업데이트 후에 렌더링됩니까? 또는 마지막 setState 업데이트 후?
user2774480


당신이 묻는 사용자 2774480에 관해서는 사용할 구현을 결정하기 위해 특정 유스 케이스에 달려 있다고 생각합니다. 체인에 여러 setStates가 사용되면 성능에 영향을 미치며 각 setState 후에 렌더링되지만 잘못되면 수정하십시오.
kurokiiru '


-1

async-await 문법은 다음과 같이 완벽하게 작동합니다 ...

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

-1

간단히 말해서-this.setState ({data : value})는 본질적으로 비동기 적이므로 호출 스택에서 벗어나서 해결되지 않으면 콜 스택으로 만 돌아옵니다.

JS의 비동기 특성과 업데이트하는 데 시간이 걸리는 이유에 대한 명확한 그림을 보려면 Event Loop에 대해 읽으십시오.

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

그 후 -

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

업데이트하는 데 시간이 걸리므로 위의 과정을 달성하려면-

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