defer() 함수에 대해 정리해보겠다.
React-Router에서는 defer() 함수를 다음과 같이 설명하고 있다.
This utility allows you to defer values returned from loaders by passing promises instead of resolved values.
defer는 데이터가 로딩되는 때를 연기해준다.
예를 들어 어떤 API가 시간이 오래 걸린다고 하면, 해당 데이터를 가져올 때까지 로딩 컴포넌트를 보여주고 싶을 수 있다. defer는 데이터가 도착이 덜 되었더라도, 컴포넌트를 미리 렌더링하라고 리액트 라우터에게 알려줄 수 있다.
기존에 라우터에 등록한 loader 함수이다.
export async function loader() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
console.log(response);
if (response.status !== 200) {
return json({ message: "POST 불러오기 실패" }, { status: 500 });
} else {
const resData = await response.json();
return resData;
}
}
defer를 사용하기 위해 수정해보자.
async function loadArticles() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
console.log(response);
if (response.status !== 200) {
return json({ message: "POST 불러오기 실패" }, { status: 500 });
} else {
const resData = await response.json();
return resData;
}
}
export function loader() {
return defer({
articles: loadArticles(),
});
}
새로운 loader 함수 안에서 loadArticles의 Promise를 기다리는 것을 원하지 않기 때문에, loader 에 async를 제거한다. 그리고 react-router-dom의 defer 함수를 가져와 loader에서 사용할 수 있다.
defer : 이 페이지에서 오갈 수 있는 모든 HTTP 요청을 객체 형태로 넣어줄 수 있다.
객체에서 키 이름은 자유롭게 선택할 수 있는데 여기서는 articles을 키로 사용하였다. 그리고 articles 키에 loadArticles를 등록하고 실행하기 위해 ()를 붙여주었다. 그래서 loader를 실행하면, loadArticles 의 리턴 값이 articles에 저장된다.
이제, 이를 사용해보자.
기존에도 라우터에 등록되어 있는 loader 리턴값을 useLoaderData()로 가져왔는데, 이번에도 똑같이 가져온다.
const { articles } = useLoaderData();
객체 분해 할당을 이용해 articles 키를 받아온다.
여기서 사용할 수 있는 특수한 컴포넌트가 2개가 있다. 바로 Await과 Suspense이다.
function ArticlesPage() {
const { articles } = useLoaderData();
return (
<div>
<Link to={"new"}>New</Link>
<p>ArticlesPage</p>
<Suspense fallback={<p>Loading...</p>}>
<Await resolve={articles}>
{(loadedArticles) => (
<ol>
{loadedArticles.map((article) => (
<li key={article.id}>
<Link to={`${article.id}`}>{article.title}</Link>
</li>
))}
</ol>
)}
</Await>
</Suspense>
</div>
);
}
Await의 resolve 프로퍼티에 loader에서 가져온 articles를 넣는다. articles의 데이터를 모두 가져오면 이제 Await 내부의 코드가 실행이 된다. 여기서는 가져온 값을 loadedArticles이라고 명명하였고, 이것을 map 함수를 사용하여 리스트로 나열하였다.
이때, articles가 load 되는 동안 Suspense의 fallback이 화면에 렌더링된다.

위와 같이 데이터를 가져오는 동안 Loading...이 표시된다. 이후 데이터가 로드가 완료되면 Loading... 문구가 사라지고 Await 내의 코드가 실행된다.