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) 사용된 라이브러리/모듈
useState
와useEffect
는 React Hook 이다.useState
는 데이터를 저장하는 공간(상태)을 만들어 주고,useEffect
는 컴포넌트가 화면에 처음 나타날 때 한 번만 실행되는 특정 작업(여기서는 서버에서 데이터를 불러우는 것)을 할 수 있게 해준다.
step 3. 코드 분석
(1) 주요 함수/클래스
- 함수/클래스 이름:
fetchPost
, 서버에서 데이터를 받아오는 비동기 함수 - 매개변수: 없음
- 반환값: 없음. 데이터를 받아와 상태로 저장하는 함수이기 때문에 반환값은 없다.
- 특이사항:
async
로 비동기 함수를 만들고await
으로 서버에서 데이터를 기다린다. 만약 서버에서 데이터를 못 받아오면 에러가 발생해서,catch
블록에서 에러 처리를 해준다.
(2) 흐름 설명
- 컴포넌트가 화면에 처음 나타날 때
useEffect
안에 있는fetchPost
함수가 실행된다.
(useEffect
: 컴포넌트가 처음 렌더링될 때 한 번만 실행되며,fetchPost
함수를 호출해 데이터를 가져온다.) fetchPost
함수는 서버에서 데이터를 불러오고, 그 데이터를setPost
라는 함수로 상태에 저장한다.
(fetchPost
: 비동기 함수로fetch
를 통해 데이터를 불러오고, 성공 시 데이터를 JSON 형식으로 변환 후setPost
로 상태에 저장한다.- 데이터가 없을 때는 “Loading…”이 화면에 보여지고, 데이터를 받아오면
post.title
을 화면에 보여준다.
(화면 렌더링: 데이터가 있으면post.title
을 화면에 보여주고, 없으면 “Loading…” 메시지를 보여준다. - 서버에서 데이터를 못 가져오면 콘솔에 에러 메시지가 찍힌다.
- 예외 처리: 네트워크 에러가 발생할 경우 콘솔에 에러 메시지를 출력한다.
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;
코드 설명
Promise.all
:- 여러 비동기 작업(여기서는
fetch
요청)을 한 번에 처리할 수 있게 도와준다. 모든 요청이 완료되면 배열로 결과를 반환한다. - 예를 들어, 첫 번째와 두 번째 게시글 데이터를 동시에 받아오고, 그 데이터를
post1
,post2
로 각각 저장한다.
- 여러 비동기 작업(여기서는
- 로딩 처리:
- 데이터를 불러오는 동안
loading
상태를true
로 두고, 데이터를 다 불러오 후에false
로 바꿔서 “Loading…” 메시지를 숨긴다.
- 데이터를 불러오는 동안
- 데이터 출력:
posts[0]
에는 첫 번째 게시글 데이터가,posts[2]
에는 두 번째 게시글 데이터가 들어있다. 이 데이터를 각각 화면에 표시해준다.
- 이 코드로 두 개의 데이터를 동시에 불러올 수 있다.
Promise.all
덕분에 데이터들이 한꺼번에 처리되니까 더 효율적으로 작동한다.