[React] useState의 비동기적 동작

Bam·2022년 3월 9일
0

React

목록 보기
22/40
post-thumbnail

setState의 비동기적 동작

함수형 컴포넌트로 간단한 카운터를 만들었습니다.

import React, {useState} from 'react';

const Counter2 = () => {
    const [count, setCount] = useState(0);

    const onClick = () => {
        setCount(count+1);
        console.log('click');

        setCount(count+1);
        console.log('click');
    }

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={onClick}>+</button>
        </div>
    );
}

export default Counter2;

실행해보기전에 동작을 예측해보자면, state의 count가 두 번 증가해서 결과적으로 버튼을 누르면 카운트가 2씩 증가할 것 같습니다.

그럼 실행해볼까요?우선 count를 1씩 증가시키는 코드는 두 번 동작했음을 알 수 있고 마지막으로 렌더링 과정을 거침을 알 수 있습니다. 그러나 카운터에 증가되는 수는 예상과는 다르게 1씩 증가했습니다.

한가지를 더 보겠습니다. 이벤트를 다음과 같이 수정해보고 실행하면...

    const onClick = () => {
        setCount(count+1);
        console.log('click');

        setCount(count+0);
        console.log('click');
    }

카운트가 하나도 증가하지 않습니다. 이러한 동작을 보이는 이유는 useState Hook의 setState가 비동기적으로 동작을 수행하기 때문입니다.

비동기를 간단히 설명하고 넘어가자면 한가지 일을 처리하는 동안 다른 작업이 기다리지 않고 동시에 수행하는 것 입니다. 예를 들어서 카페에 갔는데 개인카페라 사장님 혼자 주문받고 일하면, 손님 한 명의 주문을 받고 음료를 제조하는 동안 다른 손님은 주문도 불가능하죠. 이것이 동기 처리입니다. 하지만 직원을 두어 주문 담당과 제조담당을 따로 둔다면 손님은 주문을 계속해서 할 수 있고, 그동안 제조담당은 음료를 계속해서 제조할 수 있습니다. 이것이 비동기 처리입니다.

위의 코드를 해석해 보면 count+1이 실행되었습니다. 그리고 count+0가 실행됩니다. 만약 이것을 각자 변경 시점에 렌더링한다면 비효율적일 것 입니다. 지금이야 코드 두 줄이지만, 저런 코드가 100줄을 넘어가면 효율이 매우 나빠지면서, 카운트의 숫자도 동시에 난잡하게 변경되게 되겠죠. 동작도 비효율적이면서 이상한 동작을 하기 때문에 setState는 모든 주문(명령 코드)를 받은 후에 가장 최신의 결과를 렌더링해내게 됩니다.
그래서 위의 코드에서 결국 1증가와 0증가라는 결과를 불러오게 된 것 입니다. 공식 문서의 한 줄이 이 장황한 설명을 간단하게 이야기 하고있습니다.이러한 setState의 동작때문에 useState Hook는 비동기적으로 동작한다고 볼 수 있습니다.

함수형 업데이트

그렇다면 useState 값이 바뀔 때마다 렌더링 하는 방법은 무엇일까요? 바로 함수형 업데이트입니다. 방식은 setState를 줄 때 위 코드처럼 어떠한 값을 바로 주는 것이 아니라 함수를 통해서 전달하는 방식을 이용하는 것 입니다.

//이전 코드
    const onClick = () => {
        setCount(count+1);
        console.log('click');

        setCount(count+1);
        console.log('click');
    }
    
//함수형 업데이트 코드
    const onClick = () => {
        setCount(count => count+1);
        console.log('click');

        setCount(count => count+1);
        console.log('click');
    }

이렇게 처음에 기대했던 동작대로 2가 증가했음을 볼 수 있습니다. 더 정확하게는 2가 증가한 것이 아니고, 1이 증가한 것을 렌더링하고 바로 1을 증가한 것을 한 번 더 렌더링 했지만 동작이 매우 빠르기에 우리 눈에 2가 증가한 것 처럼 보이는 것입니다.

이처럼 state의 변경시마다 렌더링을 하고 싶다면 함수형 업데이트를 반드시 기억해주세요.

또, useCallback Hook와 함께 함수형 업데이트를 사용하면 props로 전달한 함수를 최적화 할 수 있습니다.

0개의 댓글