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.