setState는 상태를 즉시 업데이트하지 않습니다.


108

onclick 이벤트를 수행 할 때 내 상태가 변경되지 않는 이유를 묻고 싶습니다. 생성자에서 onclick 함수를 바인딩해야한다는 것을 얼마 전에 검색했지만 여전히 상태가 업데이트되지 않습니다. 내 코드는 다음과 같습니다.

import React from 'react';

import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';

import BoardAddModal from 'components/board/BoardAddModal.jsx';

import style from 'styles/boarditem.css';

class BoardAdd extends React.Component {

    constructor(props){
        super(props);

        this.state = {
            boardAddModalShow: false
        }

        this.openAddBoardModal = this.openAddBoardModal.bind(this);
    }
    openAddBoardModal(){
        this.setState({ boardAddModalShow: true });
// After setting a new state it still return a false value
        console.log(this.state.boardAddModalShow);

    }

    render() {

        return (
            <Col lg={3}>
                <a href="javascript:;" className={style.boardItemAdd} onClick={this.openAddBoardModal}>
                    <div className={[style.boardItemContainer,style.boardItemGray].join(' ')}>
                        Create New Board
                    </div>
                </a>



            </Col>
        )
    }
}

export default BoardAdd

5
대답 이 질문에 접수 한 말도 안돼. setState약속을 반환하지 않습니다. 이 일을하는 경우 때문에, 그것은 단지 일 await을 소개 한 비동기 "틱"기능으로, 그것이 일어난 상태 업데이트가 틱 동안 처리되었다있다. 보장되지 않습니다. 이 답변에서 알 수 있듯이 완료 콜백을 사용해야합니다 (상태가 업데이트 된 후 무언가를 실제로 수행해야하는 경우는 드문 경우입니다. 일반적으로 자동으로 발생하는 다시 렌더링하기 만하면됩니다).
TJ Crowder

현재 수락 된 답변을 수락하지 않거나 올바른 답변을 수락하면 다른 많은 질문에 대한 중복으로 사용될 수 있으므로 좋을 것입니다. 상단에 오답이있는 것은 오해의 소지가 있습니다.
Guy Incognito

답변:


14

이 콜백은 정말 지저분합니다. 대신 async await를 사용하십시오.

async openAddBoardModal(){
    await this.setState({ boardAddModalShow: true });
    console.log(this.state.boardAddModalShow);
}

28
말이 안 돼. React setState는 약속을 반환하지 않습니다.
TJ Crowder

17
@TJCrowder가 맞습니다. setState약속을 반환하지 않으므로 기다리면 안됩니다. 즉, 어떤 사람들에게는 이것이 왜 작동하는지 알 수 있다고 생각합니다 .await는 나머지 함수보다 먼저 호출 스택에 setState의 내부 작업을 배치하므로 먼저 처리되므로 상태가 세트. setState에 새로운 비동기 호출이 있거나 구현 된 경우이 응답은 실패합니다.이 함수를 올바르게 구현하려면 다음을 사용할 수 있습니다.await new Promise(resolve => this.setState({ boardAddModalShow: true }, () => resolve()))
Mike Richards

대체 어떻게 async this.setState({})내 문제를 해결 했습니까? 우리는 작업 코드를 가지고 있었고 더 많은 개발이 수행되었지만 앱의 해당 부분을 변경 한 것은 없습니다. setState의 두 개체 중 하나만 업데이트되어 비동기 적으로 기능이 다시 반환되고 이제 두 개체가 모두 올바르게 업데이트됩니다. 나는 도대체 무엇이 잘못되었는지 전혀 모른다.
Ondřej Ševčík

이 질문을 찾았지만이 솔루션이 저에게 효과가 없었습니다. 아직 문제를 해결하지 못했지만 여기에서 좋은 읽기를 찾았습니다. ozmoroz.com/2018/11/why-my-setstate-doesnt-work
carmolim

149

상태를 변경하는 데 약간의 시간이 필요 console.log(this.state.boardAddModalShow)하며 상태가 변경되기 전에 실행되므로 이전 값을 출력으로 얻습니다. 따라서 setState함수 에 대한 콜백에 콘솔을 작성해야 합니다.

openAddBoardModal() {
  this.setState({ boardAddModalShow: true }, function () {
    console.log(this.state.boardAddModalShow);
  });
}

setState비동기입니다. 한 줄로 전화를 걸 수없고 다음 줄에서 상태가 변경되었다고 가정 할 수 없습니다.

React 문서 에 따르면

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

setState비동기로 만들 까요?

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

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


지금까지는 좋은 생각이지만 eslint 규칙을 사용하고 있기 때문에 console.log를 사용할 수 없다면 어떨까요?
maudev

2
@maudev, eslint 규칙은 console.logs를 사용하지 못하도록하여 프로덕션으로 끝나지 않도록하지만 위의 예제는 순전히 디버깅을위한 것입니다. 및 CONSOLE.LOG 및 계정에 업데이트 된 상태를 취하는 동작으로 대체
하기 Shubham 카트리

1
콜백이 말한대로 작동하지 않으면 어떻게합니까? 내 것이 아니다!
Alex Jolig

@ShubhamKhatri 이것은 나를 위해 잘 작동했지만 상태 값을 하위 구성 요소에 소품으로 전달하려고 시도했으며 소품이 될 때 console.log원래 상태와 동일한 값을 얻었습니다.
Archie Margretts

36

다행히 setState() 콜백을받습니다. 그리고 이것이 업데이트 된 상태를 얻는 곳입니다.

이 예를 고려하십시오.

this.setState({ name: "myname" }, () => {                              
        //callback
        console.log(this.state.name) // myname
      });

따라서 콜백이 발생하면 this.state가 업데이트 된 상태입니다. 콜백에서 데이터를
얻을 수 있습니다 mutated/updated.


1
이 콜백을 사용하여 모든 함수를 전달할 수도 있습니다. initMap()
Dende

잘 했어! 마침내 내 문제를 해결했습니다. 감사합니다.
Ahmet Halilović

12

setSatate는 비동기 함수이므로 이와 같은 콜백으로 상태를 콘솔 화해야합니다.

openAddBoardModal(){
    this.setState({ boardAddModalShow: true }, () => {
        console.log(this.state.boardAddModalShow)
    });
}

7

setState()항상 구성 요소를 즉시 업데이트하지는 않습니다. 나중에 업데이트를 일괄 처리하거나 연기 할 수 있습니다. 이것은 setState()잠재적 인 함정 을 호출 한 직후 this.state를 읽도록 합니다. 대신 componentDidUpdate또는 setState콜백 ( setState(updater, callback))을 사용 하세요 .이 중 하나는 업데이트가 적용된 후에 실행됩니다. 이전 상태를 기반으로 상태를 설정해야하는 경우 아래 업데이트 프로그램 인수에 대해 읽어보세요.

setState()shouldComponentUpdate()false를 반환 하지 않는 한 항상 다시 렌더링 합니다. 변경 가능한 객체를 사용하고에서 조건부 렌더링 논리를 구현할 수없는 경우 새 상태가 이전 상태와 다를 때만 shouldComponentUpdate()호출 setState()하면 불필요한 다시 렌더링을 방지 할 수 있습니다.

첫 번째 인수는 서명이있는 업데이트 프로그램 함수입니다.

(state, props) => stateChange

state변경 사항이 적용되는 시점의 구성 요소 상태에 대한 참조입니다. 직접 변형되어서는 안됩니다. 대신 state 및 props의 입력을 기반으로 새로운 객체를 구축하여 변경 사항을 표현해야합니다. 예를 들어, props.step에 의해 state의 값을 증가시키고 싶다고 가정합니다.

this.setState((state, props) => {
    return {counter: state.counter + props.step};
});

2

상태가 업데이트되고 있는지 추적하려는 경우 동일한 작업을 수행하는 또 다른 방법은

_stateUpdated(){
  console.log(this.state. boardAddModalShow);
}

openAddBoardModal(){
  this.setState(
    {boardAddModalShow: true}, 
    this._stateUpdated.bind(this)
  );
}

이렇게하면 디버깅을 위해 상태를 업데이트하려고 할 때마다 "_stateUpdated"메서드를 호출 할 수 있습니다.


1

setState()비동기입니다. 상태가 업데이트 중인지 확인하는 가장 좋은 방법 componentDidUpdate()은에 있고 console.log(this.state.boardAddModalShow)뒤에 넣지 않는 것 this.setState({ boardAddModalShow: true })입니다.

React Docs 에 따르면

setState ()를 구성 요소를 업데이트하기위한 즉각적인 명령이 아니라 요청으로 생각하십시오. 더 나은 성능을 위해 React는이를 지연시킨 다음 한 번에 여러 구성 요소를 업데이트 할 수 있습니다. React는 상태 변경이 즉시 적용된다는 것을 보장하지 않습니다.


1

React Docs 에 따르면

React는 상태 변경이 즉시 적용된다는 것을 보장하지 않습니다. 이것은 setState ()를 호출 한 직후 this.state를 읽을 수있게하며 잠재적 으로 nature 로 인해 값을 pitfall반환 할 수 있습니다 . 대신 setState 작업이 성공한 직후에 실행 되는 콜백을 사용 하거나 일반적 으로 이러한 로직에 대신 사용 하는 것이 좋습니다 .existingasynccomponentDidUpdatesetStatecomponentDidUpdate()

예:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      counter: 1
    };
  }
  componentDidUpdate() {
    console.log("componentDidUpdate fired");
    console.log("STATE", this.state);
  }

  updateState = () => {
    this.setState(
      (state, props) => {
        return { counter: state.counter + 1 };
      });
  };
  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <button onClick={this.updateState}>Update State</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


1

후크로이 작업을 수행하려는 사람에게는 useEffect.

function App() {
  const [x, setX] = useState(5)
  const [y, setY] = useState(15) 

  console.log("Element is rendered:", x, y)

  // setting y does not trigger the effect
  // the second argument is an array of dependencies
  useEffect(() => console.log("re-render because x changed:", x), [x])

  function handleXClick() {
    console.log("x before setting:", x)
    setX(10)
    console.log("x in *line* after setting:", x)
  }

  return <>
    <div> x is {x}. </div>
    <button onClick={handleXClick}> set x to 10</button>
    <div> y is {y}. </div>
    <button onClick={() => setY(20)}> set y to 20</button>
  </>
}

산출:

Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20

-1

내가 코드를 실행하고 콘솔에서 내 출력을 확인했을 때 그것이 정의되지 않았다는 것을 보여줍니다. 주변을 검색하고 나를 위해 일한 것을 찾은 후에.

componentDidUpdate(){}

이 메서드는 constructor () 뒤에 내 코드에 추가했습니다. React Native 워크 플로의 수명주기를 확인하세요.

https://images.app.goo.gl/BVRAi4ea2P4LchqJ8


-2
 this.setState({
    isMonthFee: !this.state.isMonthFee,
  }, () => {
    console.log(this.state.isMonthFee);
  })

2
이것은 가장 많이 찬성 된 답변이 설명하는 것과 정확히 일치하지만 설명이없고 3 년 늦었습니다. 추가 할 관련성이없는 한
Emile Bergeron

-2

예, setState는 비동기 함수이기 때문입니다. 설정 상태를 작성한 직후 상태를 설정하는 가장 좋은 방법은 다음과 같이 Object.assign을 사용하는 것입니다. 예를 들어 속성 ​​isValid를 true로 설정하려면 다음과 같이하십시오.


Object.assign (this.state, {isValid : true})


이 줄을 작성한 직후 업데이트 된 상태에 액세스 할 수 있습니다.


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