sodol-dotcom

비동기 데이터 처리: async/await와 Promise.all을 활용한 다중 API 호출 본문

Troubleshooting

비동기 데이터 처리: async/await와 Promise.all을 활용한 다중 API 호출

sod0l 2024. 9. 6. 22:16

step 1. 문제 코드

코드를 접하게 된 과정

  • 비동기 데이터 처리를 연습하는 과정에서 async / await의 사용법을 익히기 위해 작성한 코드이다.
  • fetch API를 사용하여 외부 데이터(여기서는 jsonplaceholder의 post)를 불러오는 간단한 예제이다.
import { useState } from "react";
import { useEffect } from "react";
const App = () => {
const [post, setPost] = useState(null);
useEffect(() => {
const fetchPost = async () => {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts/1"
);
const data = await response.json();
setPost(data);
} catch (error) {
console.error("Error => ", error);
}
};
fetchPost();
}, []);
console.log("post", post);
return (
<div>
<h3>async / await 연습</h3>
{post ? <div>{post.title}</div> : <div>Loading...</div>}
</div>
);
};
export default App;

 

 

step 2. 코드 설명

(1) 기능 개요

  • 이 코드는 외부 API에서 데이터를 불러와 화면에 출력하는 간단한 비동기 처리 예제이다.
  • useEffect 를 사용하여 컴포넌트가 렌더링될 때 데이터를 가져오는 fetchPost 함수를 실행하고, 가져온 데이터를 setPoset 로 상태에 저장한 후 화면에 출력한다.
  • 예를 들어, 네이버 뉴스나 블로그 글을 우베에서 불러오는 걸 생각하면 비슷하다. 여기서 jsonplaceholder 라는 테스트용 API를 이용해서 서버에서 게시글 데이터를 받아오는 것을 해 본 코드이다.
import { useState } from "react";
import { useEffect } from "react";
const App = () => {
// 1. 'post'라는 상태(state)를 만들어서 서버에서 받아온 데이터를 저장할 공간을 준비한다.
const [post, setPost] = useState(null); // 처음엔 데이터가 없으니 'null'로 시작.
// 2. useEffect는 페이지가 처음 화면에 보여질 때 특정 작업(여기선 데이터 불러오기)을 해준다.
useEffect(() => {
const fetchPost = async () => {
try {
// 3. fetch() 함수로 서버에 있는 데이터를 불러운다.
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts/1" // 1번 글을 가져옴
);
const data = await response.json(); // 4. 서버에서 받은 데이터를 JSON으로 변환해서 'data'에 저장
setPost(data); // 5. 받아온 데이터를 상태인 'post'에 저장함.
} catch (error) {
console.error("Error => ", error); // 6. 데이터 불러오기 실패 시 에러 메시지를 보여줌
}
};
// 7. 데이터를 불러오는 함수를 실행함.
fetchPost();
}, []); // 빈 배열 ([])은 이 작업이 컴포넌트가 처음 렌더링될 때 한 번만 실행되게 해줌.
console.log("post", post);
return (
<div>
<h3>async / await 연습</h3>
{/* 8. post가 있으면 제목을 보여주고, 없으면 "Loading..." 메시지를 보여줌. */}
{post ? <div>{post.title}</div> : <div>Loading...</div>}
</div>
);
};
export default App;

 

(2) 특이사항

  • 비동기 처리를 위해 aync / await 을 사용했다. 이게 왜 필요하나면, 서버에서 데이터를 가져오는 동안 다른 작업도 계속할 수 있게 해주기 때문이다. 예를 들어, 네이버 뉴스를 클릭했을 때 바로 내용이 뜨는게 아니라 잠시 로딩되는 동안 페이지를 볼 수 있는 것처럼 말이다.

 

(3) 사용된 라이브러리/모듈

  • useStateuseEffectReact Hook 이다.
    • useState 는 데이터를 저장하는 공간(상태)을 만들어 주고,
    • useEffect 는 컴포넌트가 화면에 처음 나타날 때 한 번만 실행되는 특정 작업(여기서는 서버에서 데이터를 불러우는 것)을 할 수 있게 해준다.

 

 

step 3. 코드 분석

(1) 주요 함수/클래스

  • 함수/클래스 이름: fetchPost , 서버에서 데이터를 받아오는 비동기 함수
  • 매개변수: 없음
  • 반환값: 없음. 데이터를 받아와 상태로 저장하는 함수이기 때문에 반환값은 없다.
  • 특이사항: async 로 비동기 함수를 만들고 await 으로 서버에서 데이터를 기다린다. 만약 서버에서 데이터를 못 받아오면 에러가 발생해서, catch 블록에서 에러 처리를 해준다.

 

(2) 흐름 설명

  1. 컴포넌트가 화면에 처음 나타날 때 useEffect 안에 있는 fetchPost 함수가 실행된다.
    (useEffect : 컴포넌트가 처음 렌더링될 때 한 번만 실행되며, fetchPost 함수를 호출해 데이터를 가져온다.)
  2. fetchPost 함수는 서버에서 데이터를 불러오고, 그 데이터를 setPost 라는 함수로 상태에 저장한다.
    (fetchPost : 비동기 함수로 fetch 를 통해 데이터를 불러오고, 성공 시 데이터를 JSON 형식으로 변환 후 setPost 로 상태에 저장한다.
  3. 데이터가 없을 때는 “Loading…”이 화면에 보여지고, 데이터를 받아오면 post.title 을 화면에 보여준다.
    (화면 렌더링: 데이터가 있으면 post.title 을 화면에 보여주고, 없으면 “Loading…” 메시지를 보여준다.
  4. 서버에서 데이터를 못 가져오면 콘솔에 에러 메시지가 찍힌다.
  • 예외 처리: 네트워크 에러가 발생할 경우 콘솔에 에러 메시지를 출력한다.

 

 

step 4. 코드의 장단점

  • 장점:
    • 비동기 작업을 async / await 으로 쉽게 처리해서 코드가 더 직관적으로 읽기 쉬움
    • 데이터를 받아오는 동안 사용자가 기다리지 않게 “Loading…” 메시지를 보여주는 사용자 경험(UX)을 제공한다.
  • 단점:
    • 이 코드는 데이터를 한 번만 받아오기 때문에, 데이터를 다시 불러오거나 새로 고침 기능이 필요할 수 있다.
    • 오류가 발생했을 때 화면에 에러 메시지를 보여주지 않아서, 사용자는 문제가 생긴지 모를 수 있다.

 

 

step 5. 개선 방안 및 추가 학습 자료

  • 개선 방안:
    • 데이터를 주기적으로 업데이트하거나, 새로 고침 버튼을 추가할 수 있다.
    • 에러 발생 시 사용자에게 오류 메시지를 보여주고, 다시 시도할 수 있는 기능도 추가하면 더 좋을 것 같다.

 

 

step 6. 기타 메모

  • 이 코드는 기본적인 데이터 불러오기 기능을 다루고 있다. 여기서 더 복잡한 작업을 하려면 여러 데이터를 한 번에 불러오는 방법(Promise.all)이나 에러 처리 방법을 더 깊이 있게 공부할 필요가 있다.
import { useState, useEffect } from "react";
const App = () => {
// 두 개의 상태: 첫 번째와 두 번째 게시글을 저장할 상태
const [posts, setPosts] = useState([null, null]);
const [loading, setLoading] = useState(true); // 로딩 상태 추가
useEffect(() => {
const fetchPosts = async () => {
try {
// 두 개의 API 요청을 Promise.all로 동시에 처리
const [post1, post2] = await Promise.all([
fetch("https://jsonplaceholder.typicode.com/posts/1").then((res) => res.json()),
fetch("https://jsonplaceholder.typicode.com/posts/2").then((res) => res.json())
]);
setPosts([post1, post2]); // 두 개의 데이터를 상태에 저장
setLoading(false); // 데이터를 다 불러오면 로딩 상태를 false로 설정
} catch (error) {
console.error("Error => ", error); // 에러가 발생하면 콘솔에 에러 메시지 출력
}
};
fetchPosts(); // 데이터 불러오기 함수 실행
}, []);
return (
<div>
<h3>Promise.all 연습</h3>
{loading ? (
<div>Loading...</div>
) : (
<div>
<div>첫 번째 게시글 제목: {posts[0]?.title}</div>
<div>두 번째 게시글 제목: {posts[1]?.title}</div>
</div>
)}
</div>
);
};
export default App;

코드 설명

  1. Promise.all :
    • 여러 비동기 작업(여기서는 fetch 요청)을 한 번에 처리할 수 있게 도와준다. 모든 요청이 완료되면 배열로 결과를 반환한다.
    • 예를 들어, 첫 번째와 두 번째 게시글 데이터를 동시에 받아오고, 그 데이터를 post1 , post2 로 각각 저장한다.
  2. 로딩 처리:
    • 데이터를 불러오는 동안 loading 상태를 true 로 두고, 데이터를 다 불러오 후에 false 로 바꿔서 “Loading…” 메시지를 숨긴다.
  3. 데이터 출력:
    • posts[0] 에는 첫 번째 게시글 데이터가, posts[2] 에는 두 번째 게시글 데이터가 들어있다. 이 데이터를 각각 화면에 표시해준다.
  • 이 코드로 두 개의 데이터를 동시에 불러올 수 있다. Promise.all 덕분에 데이터들이 한꺼번에 처리되니까 더 효율적으로 작동한다.