[TIL] setState에 대한 의문

Mustache 🥸·2021년 6월 2일
0

React

목록 보기
3/6
post-custom-banner

잉!?

Westagram을 리액트로 변환하는 과정 중에 처음으로 마주한 setState의 비동기화로 인한 나만의 오류???를 발견했다.
이건 오류라기보다는 setState의 비동기화로 인해 생긴 현상이라고 보면 좋을것 같다.
먼저 아래와 같이 inputValue에 따른 특정 이벤트를 발생시키는 코드를 보자.

import React from 'react';

class SetState extends React.Component {
  constructor() {
    super();
    this.state = {
      inputText: '',
      color: '',
    };
  }

  validateInput = () => {
    const { inputText } = this.state;

    inputText.length >= 5 ? this.setState({ color: 'blue' }) : this.setState({ color: 'red' });
  };

  handleOnChange = (e) => {
    this.setState({
      [e.target.name]: e.target.value,
    });
    this.validateInput();
  };

  render() {
    return (
      <div>
        <input type="text" name="inputText" onChange={this.handleOnChange} />
        <p style={{ color: this.state.color }}>{this.state.inputText}</p>
      </div>
    );
  }
}

export default SetState;

내가 위처럼 validateInput이라는 함수에서 inputText의 길이가 5이상일 때, p 태그의 글자가 파란색, 그 이하일때는 빨간색이 되게 설정했다. 하지만 실제로 화면으로 돌려보면 내 맘처럼 되지는 않는다.

난 분명 글자를 쳤는데, console.log(inputText)는 한박자씩 늦게 말해주고, 지워주는 것 역시 같다. validateInput 역시 이벤트가 늦게 발생한다.

왜 그런것일까?
리액트 공식문서는 setState의 특성에 대하여 이렇게 말한다.

setState()는 컴포넌트를 항상 즉각적으로 갱신하지는 않습니다. 오히려 여러 변경 사항과 함께 일괄적으로 갱신하거나, 나중으로 미룰 수도 있습니다. 이로 인하여 setState()를 호출하자마자 this.state에 접근하는 것이 잠재적인 문제가 될 수 있습니다. 그 대신에 componentDidUpdate 또는 setState의 콜백(setState(updater, callback))을 사용하세요. 둘 다 갱신이 적용된 뒤에 실행되는 것이 보장됩니다

그렇다. 그냥 setState가 즉각적으로 전달받은 state로 값을 바꾸는 것이 아니라 이전의 리액트 엘리먼트 트리와 전달받은 state가 적용된 엘리먼트 트리를 비교하는 작업을 거치고, 최종적으로 변경되는 부분만 DOM에 적용한다.

이 문제를 해결하기 위해선 공식문서에 언급된것 처럼 componentDidUpdate를 활용하거나 setState의 콜백을 사용해야한다.
나는 setState의 콜백을 이용해보았다.

handleOnChange = (e) => {
    this.setState(
      {
        [e.target.name]: e.target.value,
      },
      () => {
        this.validateInput();
      },
    );
  };

위처럼 setState의 콜백함수로 validateInput을 실행시키니 아래 화면처럼 내가 의도한대로 진행됨을 볼수있다.

어렵다.! 리액트! setState는 맨 처음 개념인데도 이렇게 햇갈릴줄이야?

post-custom-banner

0개의 댓글