react 자바스크립트의 sync / async 관련 상식

바다캔디·2025년 7월 3일

리액트공부

목록 보기
38/39

자바스크립트의 sync / async 관련 상식

자바스크립트는 일반적인 코드를 작성하면 synchronous 하게 처리됨.
번역하면 동기방식.
코드 적은 순서대로 윗줄부터 차례로 코드가 실행된다는 뜻.

근데 자바스크립트는 이상한 함수들을 사용하면 asynchronous 하게 코드실행이 가능
번역하면 비동기방식.
ajax, 이벤트리스너, setTimeout 이런 함수들을 쓸 때 그런 현상이 일어남.
ajax 부터가 '비동기통신'.
이런 함수들은 처리시간이 오래걸림.
ajax를 예로 들면 인터넷 상황이 안좋으면 코드 실행이 10초도 걸릴 수 있음.
그래서 ajax 요청하는 코드들은 순차적으로 실행되지 않고 완료되면 실행됨.
자바스크립트라는 언어의 특징이자 장점

setState가 async임. 큰일남.

state 변경함수들은 전부 asynchronous (비동기적) 으로 처리됨.
그니까 setName()이 오래걸리면 이거 제껴두고 다른 밑에 있는 코드들부터 실행됨.

그래서 뭔가 예상치 못한 문제가 생길 수 있습니다.
아래는 예시코드.
대충 버튼을 누르면 나이를 먹는 코드.
count state가 3 이상이면 age에 +1을 멈춰야 함.
근데, 22에서 멈춰야하는데 23에서 멈춤.
이유는 자바스크립트의 async라는 특징 때문에.

왜 이런 끔찍한 일이 벌어진거죠?

state 변경함수는 async 하게 처리되는 함수기 때문에 완료되기까지 시간이 오래걸리면 제쳐두고 다음 코드를 실행.
state 변경함수는 실행이 오래 걸려서 제껴두고 if문을 체크해버려서, 3번이상 버튼을 클릭해도 age에 +1이 되버림.

//App.jsx
  //async 테스트용
  let [count, setCount] = useState(0);
  let [age, setAge] = useState(20);
.
.
.

      <div>async 테스트용 버튼입니다. 옆에가 나이임 {age}</div>
      <Button
        onClick={() => {
          setCount(count + 1);
          if (count < 3) {
            setAge(age + 1);
          } else {
            console.log("3번이상은 안됩니다");
          }
        }}
      >
        나이먹는 버튼
      </Button>

해결법 중 하나.

useEffect 활용.
렌더링 될 때, 특정 state의 변경 시에 동작하는 useEffect를 활용하여 이걸 벗어나보자.

  //async 테스트용 state
  let [count, setCount] = useState(0);
  let [age, setAge] = useState(20);
.
.
.

  //async 테스트용 useEffect
  useEffect(() => {
    if (count != 0 && count < 3) {
      setAge(age + 1);
    } else {
      console.log("3번이상 클릭불가");
    }
  }, [count]);
.
.
.
      <div>async 테스트용 버튼입니다. 옆에가 나이임 {age}</div>
      <Button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        나이먹는 버튼
      </Button>

다른 방법은 없나요?

처음 페이지 로드시 useEffect 실행을 막는 코드를 알아서 검색해서 적용해서 사용해도 될듯.

useRef같은걸 적용해보자.

그게 뭔데요

React에서 DOM에 직접 접근하거나, 컴포넌트 렌더링 사이에 값을 기억하고 싶을 때 사용하는 훅. useEffect 초기 실행을 막을 수 있음.

  • ref.current에 값을 저장 가능.
  • 이 값은 렌더링이 다시 일어나도 초기화 X.
  • 값을 변경해도 컴포넌트가 리렌더링 X.

즉, true false 같은 flage값을 저장하여,
useEffect 같이 렌더링 시 실행되는 부분에 사용하기 적합한 hook.


import { useEffect, useRef, useState } from 'react';

function ExampleComponent() {
  const [count, setCount] = useState(0);
  const didMount = useRef(false);

  useEffect(() => {
    // useRef을 기본 false로 설정. 렌더링 시 일어나는 useEffect 초기 실행을 막음.
    if (didMount.current) {
      console.log('count 변경됨:', count);
    } else {
      didMount.current = true; // 첫 마운트 시에는 실행 막고 플래그 설정
    }
  }, [count]);

  return (
    <div>
      <p>카운트: {count}</p>
      <button onClick={() => setCount(prev => prev + 1)}>카운트 증가</button>
    </div>
  );
}

0개의 댓글