์ต๊ทผ ๋๋ฃ๋ถ์ด "SSR ํ์ด์ง์์ ๋ฏธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๊ฒฝ์ฐ useQuery ์ isLoading ์ด true ์ธ ๊ฒฝ์ฐ๊ฐ ์์ด์?" ๋ผ๋ ์ง๋ฌธ์ ๋์ก๋๋ฐ, ์ด ์ง๋ฌธ์ ๋ํ ๋๋ต์ ์๊ฐํ๋ค๊ฐ ์ฌ๋ฌ ์๋ฌธ์ด ์๊ฒจ ๊ธ๋ก ์ ๋ฆฌํด๋ณธ๋ค.
์ฉ์ด ์ ๋ฆฌ
- ์๋ฒ์ฌ์ด๋ : ์น์๋ฒ์ ์๋ฒ ์ชฝ ์ฝ๋ ์คํ
- ํด๋ผ์ด์ธํธ์ฌ์ด๋ : ์น์๋ฒ์ ํด๋ผ์ด์ธํธ ์ชฝ ์ฝ๋ ์คํ
- SSR : ServerSideRendering
- CSR : ClientSideRendering
- ์๋ฒ : api ๋ฅผ ์ ๊ณตํ๋ ์ค์ ์๋น์ค ์๋ฒ
์์ ์ฝ๋: SSR + useQuery
๋๋ ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๊ณ ์์๋ค.
// Next.js ์ ํ์ด์ง ์ปดํฌ๋ํธ
export const getServerSideProps = async () => {
const data = await fetchData();
return { props: { dehydratedState: dehydrate(queryClient) } };
};
const Page = () => {
const { data, isLoading } = useQuery(['key'], fetchData);
if (isLoading) {
return <Spin />;
}
return <div>{data}</div>;
};
getServerSideProps ๋ด๋ถ ๋ก์ง์ ์น์๋ฒ(์๋ฒ์ฌ์ด๋)์์ ์คํ๋๋ค.
์๋ฒ์ฌ์ด๋์์ ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐ์์ค๊ณ , dehydrate ๋ฅผ ํตํด React Query ์บ์์ ๋ฃ์ด์ค๋ค.
์๋ฒ์ฌ์ด๋์์ ๋ฏธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ฃผ๊ธฐ ๋๋ฌธ์, ํด๋ผ์ด์ธํธ์์๋ useQuery ์ ๋ฐํ๊ฐ์ธ isLoading ์ด ํญ์ false ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด ์ฝ๋๊ฐ ์๋ฏธ๋ ์์๋๊ฑธ๊น? ๐ค
๋ฐ๋ฉด CSR์ ๊ฒฝ์ฐ๋?
CSR ํ์ด์ง์์๋ ์๋ฒ์ฌ์ด๋์์ ๋ด๋ ค์ค๋ ๋ฐ์ดํฐ๊ฐ ์๊ธฐ ๋๋ฌธ์, useQuery๋ ํด๋ผ์ด์ธํธ์์ ์ฒ์์ผ๋ก fetching ์ ์ํํ๋ค. ๋ฐ๋ผ์ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ธฐ ์ ์๋ isLoading ๊ฐ์ด true ์ด๋ค. ์ฆ, isLoading ์ ๊ฐ์ง๊ณ ๋ก๋ฉ UI ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ฝ๋๊ฐ ํ์ํ๋ค.
SSR ํ์ด์ง ๊ฐ ์ด๋ ์์ ๋์์?
๊ฐ์ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ํ์ด์ง๋ก ์ด๋ํ ๋, Next.js ์์๋ ๋ณดํต Next Link ๋ Next Router๋ฅผ ์ฌ์ฉํด์ ์ด๋ํ๋ค.
export const Home = () => {
return (
<div>
<h1>Home</h1>
<Link href="/about" prefetch={true}>
Go to About
</Link>
</div>
);
}
import { useEffect } from 'react';
import { useRouter } from 'next/router';
export const Home = () => {
const router = useRouter();
useEffect(() => {
router.prefetch('/about');
}, [router]);
const goToAbout = () => {
router.push('/about');
};
return (
<div>
<h1>Home</h1>
<button onClick={goToAbout}>Go to About</button>
</div>
);
};
์ด ๋, SSR ํ์ด์ง๋ก ์ด๋ ์ prefetch ๋์์ด Next ์ ๋ฒ์ ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค.
ํญ๋ชฉ | Next.js 12 ์ดํ | Next.js 13 |
prefetch ๋์ | _next/data JSON ๋ฏธ๋ฆฌ ๋ฐ์ | ์์ |
ํด๋ฆญ ์ ์๋ต ๋ฐฉ์ | ํด๋ผ์ด์ธํธ์์ hydrate | ์๋ฒ๊ฐ HTML์ ๋ ๋๋ง |
์ด์ ์๋ SSR ํ์ด์ง์ ๋ํ Next Link ๊ฐ ์๋ค๋ฉด, ๋ฏธ๋ฆฌ ํด๋น ํ์ด์ง์ ์๋ฒ ์ฌ์ด๋ ๋ก์ง์ ์คํํ์ฌ pageProps ๋ฐ์๋์๋ค.
์ฌ๋ด์ผ๋ก ์ด๋ก ์ธํด ์ด์๋ฅผ ๊ฒช์ ์ ๋ ์๋๋ฐ, ๋ฐฐํฌ๋ฅผ ํ๋ฉด ์ด pageProps๋ฅผ ๋ฐ์์ค๋ hash ๊ฐ์ด ๋ฐ๋๊ฒ ๋์ด, ์ ์ ๊ฐ ๋ณด๊ณ ์๋ ํ์ด์ง์ Next LInk prefetch ๊ฐ ๋ชจ๋ 404 ์๋ฌ๋ก๊ทธ๋ก ๋จ๋ ๊ฒฝ์ฐ๊ฐ ์์๋ค. ์ด ์ด์๋ฅผ ๋ง์ฃผํ ํ "Next LInk ๋ก ๋์ด ์์ผ๋ฉด ์๋ฒ ์ฌ์ด๋์์ ์คํํ ๋ก์ง์ ๋ฏธ๋ฆฌ ์คํํด๋๋๊ตฌ๋" ํ๊ณ ์๊ฐํ๊ณ ์์๋๋ฐ Next 13 ๋ฒ์ ์ดํ์ ์ด ๋์์ด ๋ฐ๋์๋ค.
- 9๋ฒ์ ~ 12๋ฒ์ : SSR ํ์ด์ง์ ๋ํ Next Link ๊ฐ ์๋ค๋ฉด, ์๋ฒ ์ฌ์ด๋ ๋ก์ง์ ๋ฏธ๋ฆฌ ์คํํ๋ ์์ผ๋ก prefetch๊ฐ ๋์ํ๋ค. ๊ณต์๋ฌธ์ ๊ณต์๋ฌธ์2
- 13๋ฒ์ : ๊ธฐ๋ณธ์ ์ผ๋ก prefetch ํ์ง ์๊ณ , SSR ํ์ด์ง๋ก ์ด๋ ์ ์๋ฒ ์ฌ์ด๋๊ฐ ๋์ํ์ฌ HTML์ ๋ ๋๋งํ๋ค. ๊ณต์๋ฌธ์
- prefetch ์ค์ ์ ํตํด ์ผค ์ ์๋ค.
- ๊ฐ๋ฐ๋ชจ๋์์๋ prefetch ๊ฐ ์คํ๋์ง ์๋๋ค.
๋ฒ์ ์ ๋ฐ๋ผ prefetch ์ ๋์์ด ๋ค๋ฅผ ์๋ ์์ง๋ง, ์ด๋ค ๋ฐฉ์์ผ๋ก๋ SSR ํ์ด์ง๋ค์ ํญ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์จ ์ํ์ด๋ฏ๋ก isLoading ์ด false ์ด๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก useQuery์ isLoading์?
์ํฉ | useQuery์ isLoading ๊ฐ |
SSR ์ง์ (getServerSideProps) | false |
CSR ์ง์ (ํด๋ผ์ด์ธํธ ๋ ๋๋ง) | true |
SSR ํ์ด์ง ๊ฐ ์ด๋ (13๋ฒ์ ์ดํ) | false |
SSR์์๋ ํญ์ false ์ด๊ณ , CSR ์์๋ true ์ด๋ค. ๋ฐ๋ผ์, SSR ๋ก ๊ตฌ์ฑ๋ ํ์ด์ง์์ ์๋ฒ์ฌ์ด๋์์ ๋ถ๋ฌ์ค๋ ์๋ฒ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ isLoading ์ฝ๋๋ฅผ ์์ฑํ์ง ์์๋ ๋๋ค.
์๊ฐํด๋ณด๋ฉด ๋น์ฐํ ์ฌ์ค์ด์ง๋ง, ๋ฏธ์ฒ ์์ํ์ง ๋ชปํ์ ๋๋ ๊ด์ฑ์ ์ผ๋ก isLoading์ ๋ํ ์ฝ๋๋ฅผ ์์ฑํด์๋ ๊ฒ ๊ฐ๋ค.
์ด๋ฒ์ ๋๋ฃ์ ์ง๋ฌธ์ ๊ณ๊ธฐ๋ก useQuery์ SSR์ ๊ด๊ณ๋ฅผ ๋ค์ ๋ค์ฌ๋ค๋ณด๋ฉด์, ์์ฐ์ค๋ฝ๊ฒ Next.js์ prefetch ๋์ ๋ณํ๊น์ง ์ดํด๋ณด๊ฒ ๋์๋ค.
'์น (WEB) > ๊ณต๋ถ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ธ๋ผ์ฐ์ ] ์ธํฐ๋ท ์์ ํด๋ผ์ด์ธํธ - ์๋ฒ ํต์ ๊ณผ์ (3) | 2025.02.09 |
---|---|
์น๊ฐ๋ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ฑ๊ฐ๋ฐ ์์ด๋ณด๊ธฐ :: ๋ ๋ค ํด๋ณธ ๊ฐ๋ฐ์ ๐ (1) | 2024.03.24 |
Font Glyph (0) | 2023.09.16 |
[Typescript] ๊ตฌ์กฐ์ ํ์ดํ๊ณผ ๋ ํ์ดํ (1) | 2023.04.16 |
[Virtualized List] #3. ๊ฐ์๋ฆฌ์คํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋น๊ต (2) | 2023.01.28 |
Comment