
์ ๋ฒ ๊ธ์ ์ด์ด ์ด๋ฒ ํฌ์คํ
์์๋ ์ ๊ฐ ์ด๋ป๊ฒ Suspense ์ปดํฌ๋ํธ์
useSuspenseQuery ๋ฅผ ๋์
ํ์ฌ Skeleton UI๋ฅผ ๊ตฌํํ์๋์ง์ ๋ํด ํฌ์คํ
ํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ์ด๋ฒ ๊ฐ์ธ ๊ณผ์ ๋ https://restcountries.com ์์ ์ ๊ณตํด์ฃผ๋
API๋ฅผ ํ์ฉํด ๋๋ผ์ ์ ๋ณด๋ค์ ๋ณด์ฌ์ฃผ๋ ๊ณผ์ ์์ต๋๋ค.
๋ฐ๋ก ํ์ด์ง๋ค์ด์
์ ๋ํ ์๋ด๋ ์์ด, ๋ชจ๋ ๋๋ผ์ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ๊ฐ์ ธ์ค๋
https://restcountries.com/v3.1/all API๋ฅผ ํธ์ถํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ต๋๋ค.
ํ์ง๋ง ์๋ก๊ณ ์นจ์ ํ ๋๋ง๋ค ์๋์ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.

์ด ๊ฐ์ ธ์ฌ ๋๋ผ์ ๋ฐ์ดํฐ๋ 250๊ฐ์๊ณ , ์ด ๋ฐ์ดํฐ๋ฅผ ํ๋ฒ์ ๋ถ๋ฌ์์ ๋ฆฌ๋ ๋๋ง์ ๋ฐ์์์ผ๋ณด๋
์์ ๊ฐ์ด ๋๋ผ์ ์ ๋ณด๊ฐ ์ด์ํ๊ฒ ์ง ! ํ๊ณ ๋ํ๋๋ ๋ ์ด์์ ์ํํธ ํ์์ด ๋ฐ์ํ์์ต๋๋ค.
ํ์ฌ ์ ์ ํ๊ฒฝ์์๋ ๋ถ๊ณผ 1์ด ํน์ 1.5์ด๋ง์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๋ถ๋ ค์์ง์ง๋ง
์ข์ง ์์ ํ๊ฒฝ์์ ์น์ฌ์ดํธ์ ์ ์ํ๋ค๋ฉด ์ต์
์ ์ํฉ์์๋ 5์ด ํน์ ๊ทธ ์ด์์ ์๊ฐ์ด ์ง๋๋
์๋ฌด๊ฒ๋ ๋ณด์ด์ง ์๋ ํ์์ด ๋ฐ์ํ๊ฒ ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๊ณ ,
๊ทธ ์ ์ ๋ ์น์ฌ์ดํธ๊ฐ ์๋์ ํ์ง ์๋๊ฒ์ผ๋ก ํ๋จํ๊ณ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๊ธฐ ์ ํ๋ฉด์ ๋ซ์๋ฒ๋ฆด์๋ ์๋ค๊ณ ์๊ฐํ์์ต๋๋ค.
๋ฐ๋ผ์ ์กฐ๊ธ ๋ ์์ฐ์ค๋ฌ์ด UX๊ฐ ๋ญ๊ฐ ์์๊น.. ํ๋ฉฐ ์๊ฐํ๋ ๋์ค Skeleton UI๊ฐ ๋ ์ฌ๋ผ
๊ตฌํ์ ๊ฒฐ์ ํ๊ฒ ๋์์ต๋๋ค.
useQuery ํ
์์ ์ ๊ณตํ๋ isFetching ๊ณผ ๊ฐ์ ์ํ๋ก ์ฌ์ฉํ๋ค๋จ์ํ๊ฒ Skeleton UI๋ฅผ ์ ์ฉ์ํค๋ ๋ฐฉ๋ฒ์ค์๋ ์์ ๊ฐ์ ๋ฐฉ๋ฒ๋ ์์์ต๋๋ค.
๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๋ ๋๋ง์ ํด์ฃผ๋ ์ปดํฌ๋ํธ ๋ด์์ ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ํตํด
isFetching ์ํ๊ฐ true ๋ผ๋ฉด Skeleton UI๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ,
isFetching ์ํ๊ฐ false ๋ผ๋ฉด ์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฐฉ๋ฒ์
๋๋ค.
Suspense ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋คReact Docs๋ฅผ ํ๋ฐฉํ๋ ๋์ค, <Suspense> ๋ผ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฐ๊ฒฌํ๊ฒ ๋์์ต๋๋ค.
Suspense ์ปดํฌ๋ํธ๋ ์์ ์์๊ฐ ๋ก๋๋๊ธฐ ์ ๊น์ง ํ๋ฉด์ ๋์ฒด UI๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ปดํฌ๋ํธ๋ก
์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํด์๋ ๊ตฌํ์ ํ ์ ์์์ต๋๋ค.
์ด๋ค ๋ฐฉ์์ ์ฌ์ฉํด ๊ตฌํํ ์ง์ ๋ํด ๊ณ ๋ฏผํด๋ณด์๋๋ฐ, ๊ณ ๋ฏผ์ ์ ์ ๋ฅผ ์๋์ ๊ฐ์ด ์ค์ ํ๊ณ ๊ฒฐ์ ํ์์ต๋๋ค.
์ด๋ป๊ฒ ๊ตฌํํด์ผ ํ๋ก์ ํธ์ ์ฌ์ด์ฆ๊ฐ ์ปค์ ธ๋ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ๊ณ ๊ฐ๋ ์ฑ์ด ์ ํ๋์ง ์์๊น?
useQuery ํ
์์ ์ ๊ณตํ๋ isFetching ๊ณผ ๊ฐ์ ์ํ๋ก ์ฌ์ฉํ๋คSuspense ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋คPromise ๋ฅผ catchํด fallback ๋ก๋๋ฅผ ํ์ํด์ฃผ๊ณ ,Suspense ์ปดํฌ๋ํธ๋ Suspense๊ฐ ๊ฐ๋ฅํ ๋ฐ์ดํฐ๋ง ์ปดํฌ๋ํธ๋ฅผ ํ์ฑํ ์์ผ์ค๋ค.useEffect ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด๋ถ์์ ๊ฐ์ ธ์ค๋ ๋ฐ์ดํฐ๋ ๊ฐ์งํ์ง ์๋๋ค.์์ ์ฅ์ ๊ณผ ๋จ์ ์ ๋น๊ตํด๋ณด๋ฉฐ ์๊ฐํด๋ณด์์๋, 2๋ฒ์ ๋ฐฉ์์ด ์ ๊ฐ ์๊ฐํ๋
๊ตฌํ ๋ฐฉ์์ ๋ ์ ํฉํ๋ค๊ณ ํ๋จํด Suspense ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ ๊ตฌํํ๊ธฐ๋ก ๊ฒฐ์ ํ์์ต๋๋ค.
Suspense ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ์ค๋ค.// App.tsx
<Suspense>
<CountryList />
</Suspense>
// CountryItemSkeleton.tsx
export const CountryItemSkeleton = () => {
return (
<div className="flex h-[260px] w-[292px] animate-pulse flex-col items-center rounded bg-gray-300 p-4 shadow-md" />
);
};
๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ์ค์ ๋ณด์ฌ์ค, ์ฆ Skeleton UI๋ก ์ฌ์ฉํด์ค ์ปดํฌ๋ํธ๋ฅผ ์ ์ํด์ค๋๋ค.
// App.tsx
<Suspense
fallback={Array.from({ length: 20 }).map((_, idx) => (
<CountryItemSkeleton key={idx} />
))}
>
<CountryList />
</Suspense>
๊ทธ๋ฆฌ๊ณ ๊ฐ์ธ์ฃผ์๋ Suspense ์ปดํฌ๋ํธ์ props๋ก ์ค์ผ๋ ํค ์ปดํฌ๋ํธ๋ฅผ ๋ฃ์ด์ค๋๋ค.
๋๋ผ์ ๋ฐ์ดํฐ๋ ์ด 250๊ฐ๊ฐ ์ค๋๋ฐ ์ค์ผ๋ ํค์ผ๋ก ๋ณด์ฌ์ค์ผํ๋ ๋ฐ์ดํฐ์ ์์ ์ผ๋ง์ ๋๋ก ํด์ผ ์ ๋นํ๊ฑด์ง,
Suspense ์ปดํฌ๋ํธ๋ฅผ ์์ ๊ฐ์ด ์ฌ์ฉํด์ ๋ณด์ฌ์ฃผ๋๊ฒ์ด ๋ง๋๊ฑด์ง์ ๋ํ ๊ณ ๋ฏผ์ด ์์์ต๋๋ค.
์ด ๋ถ๋ถ์ ์ง๋ฌธ์ ํตํด ๋ต์ ์ป์ด์ผํ๋ ๋ถ๋ถ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
CountryList ์ปดํฌ๋ํธ์ ๋ก์ง์ ์์ฑํด์ค๋ค.// CountryList.tsx
const CountryList = () => {
const { data: countryList } = useSuspenseQuery({
queryKey: ["countryList"],
queryFn: () => api.country.getAllCountry(),
});
return (
<ul className="flex flex-wrap justify-center gap-4">
{countryList.map((country) => (
<CountryItem
key={country.name.common}
country={country}
/>
))}
</ul>
);
};
export default CountryList;
๊ธฐ์กด์๋ useQuery ํ
์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง์ ๋ง๋ค์์ง๋ง,
์ด์งธ์์ธ์ง Suspense ์ปดํฌ๋ํธ๊ฐ ์๋์ ํ์ง ์์์ต๋๋ค.
๋ฌธ์ ๋ฅผ ๋ง์ฃผํ๊ณ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ ๋์ค, React ๊ณต์๋ฌธ์์ Suspense ์ปดํฌ๋ํธ ์ฌ์ฉ๋ฒ์ ๋ณด์๋๋ฐ
์์์ ์ ์ด๋์๋ฏ์ด Suspense ์ปดํฌ๋ํธ๋ Suspense ๊ฐ ๊ฐ๋ฅํ ๋ฐ์ดํฐ์๋ง ํ์ฑํ๊ฐ ๋ฉ๋๋ค.
๋ฐ๋ผ์ ๊ธฐ์กด์ ์ฌ์ฉํ๊ณ ์์๋ ํ
์ธ useQuery ๋์ useSuspenseQuery ํ
์ ์ฌ์ฉํด์ผ
์ ์์ ์ผ๋ก ์๋์ด ๋๋๊ฒ์ ํ์
ํ๊ณ , ์์ ํ์์ต๋๋ค.
์ด ๊ณผ์ ์์๋ ์ญ์ Tanstack Query ๊ณต์๋ฌธ์๋ฅผ ๋ณด๋ฉฐ ํด๊ฒฐํ์์ต๋๋ค.



ํจ์ฌ ์์ฐ์ค๋ฝ์ง ์๋์?
์ ๋ ์ด ๊ธฐ์ ์ ๋์
ํ๋ฉด์ ๊ฐ์ธ์ ์ผ๋ก๋ ๊ต์ฅํ ๋ฟ๋ฏํ์ต๋๋ค.
์์ผ๋ก๋ ๊ฐ์ธํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ์ ์ ์ ์
์ฅ์์๋ ๋ฌด์์ด ๋ถํธํ ๊น,
๊ทธ๊ฒ์ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ์ด๋ค ๋ฐฉ์์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ผํ ๊น์ ๋ํด์
๊ณ ๋ฏผ์ ๋ง์ด ํ๋ ค๊ณ ๋
ธ๋ ฅํด์ผ๊ฒ ์ต๋๋ค.