OI7MI

[React] API 호출 .then() 대신 async-await 처리 본문

프론트엔드/React

[React] API 호출 .then() 대신 async-await 처리

OI7MI 2026. 1. 13. 02:01

리액트에서 외부 데이터를 가져올 때 보통 fetch를 사용한다
예전에는 .then()을 활용한 체이닝 방식이 많이 쓰였지만
요즘은 가독성과 유지보수 측면에서 async/await 방식이 사실상 표준처럼 사용된다.


 

then() vs async-await

기존 방식→ .then() 체이닝

.then()을 계속 이어 붙이다 보면 코드가 점점 길어지고 비동기 흐름을 한눈에 파악하기 어려워진다

useEffect(() => {
  fetch(`https://yts.mx/api/v2/list_movies.json`)
    .then((response) => response.json())
    .then((json) => {
      setMovies(json.data.movies);
      setLoading(false);
    });
}, []);
개선된 방식→ async-await

비동기 로직을 별도의 함수로 분리하여 동기 코드(위에서 아래로 실행되는 코드)처럼 보이게 만든다

import { useEffect, useState } from "react";

function App() {
  const [loading, setLoading] = useState(true);
  const [movies, setMovies] = useState([]);

  const getMovies = async () => {
    try {
      const response = await fetch(
        `https://yts.mx/api/v2/list_movies.json?minimum_rating=9&sort_by=year`
      );
      
      // fetch는 HTTP 에러를 자동으로 throw하지 않기 때문에 직접 체크
      if (!response.ok) {
        throw new Error("서버 응답 오류");
      }
      
      const json = await response.json();
      setMovies(json.data.movies);
      
    } catch (error) {
      console.error("데이터 로딩 실패:", error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    getMovies();
  }, []);

  return (
    <div>
      {loading ? <h1>Loading...</h1> : (
        <ul>
          {movies.map((movie) => (
            <li key={movie.id}>{movie.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

 

 


 

2. 비동기인데 왜 await로 기다릴까?

 

 

비동기를 공부하다 보면 이런 의문이 생긴다
“비동기는 안 기다리는 거라면서 왜 await(기다리다)를 쓰는 걸까?”
핵심은 '어디가 멈추느냐'의 차이다

 

  1. 전체(브라우저)는 멈추지 않는다 (비동기)
    • getMovies 함수가 데이터를 가져오는 동안, 리액트의 다른 기능이나 브라우저의 스크롤, 클릭 이벤트는 멈추지 않고 정상 작동한다. 이것이 비동기 처리의 본질인 'Non-blocking'이다.
  2. 함수 내부에서는 순서가 필요하다 (await)
    • 하지만 getMovies라는 함수 내부에서는 이야기가 다르다. 서버에서 응답(response)이 와야 JSON으로 변환을 하고, 변환이 완료되어야 State를 업데이트할 수 있다.
    • await는 "비동기 작업이 완료될 때까지 '이 함수 안에서만' 잠깐 기다려줘"라고 명령하는 것.

💡 정리하자면: 비동기 처리는 사용자가 느끼는 웹사이트 전체의 흐름을 멈추지 않게 하기 위해 사용하고, await개발자가 의도한 로직의 순서함수 내부에서 보장받기 위해 사용한다.

 

 


 

 async-await 사용 시 주의할 점 

async 함수는 항상 Promise를 반환한다
그래서 useEffect의 첫 번째 인자로 직접 async () => {}를 넣을 수 없다.
(별도 함수를 만들어 호출해야 함)
// ❌ 잘못된 예
useEffect(async () => {
  ...
}, []);


// 👉 대신 비동기 함수를 선언한 뒤 호출
useEffect(() => {
  getMovies();
}, []);

 

초기값 설정
movies.map을 사용한다면 초기 상태값을 useState([])처럼 빈 배열로 설정해야 된다
데이터가 오기 전 undefined 에러를 방지할 수 있음 (즉 초기 상태값은 반드시 맞는 타입으로 설정한다)
const [movies, setMovies] = useState([]);
에러 처리 
.catch() 대신 → try...catch문이 의미파악과 디버깅에 훨씬 유리할뿐만 아니라 예외 처리가 훨씬 직관적이다

 

 

 


정리

async/await는 비동기 코드를 동기 코드처럼 작성할 수 있게 해주는 자바스크립트의 강력한 문법이다.

이제 복잡한 .then() 체이닝 대신 가독성 좋은 async/await 패턴에 익숙해지면 React에서의 데이터 처리 흐름이 훨씬 명확해진다.