ํจ์ํ ํ๋ก ํธ์๋์์ ์์กด์ฑ ์ ์ดํ๊ธฐ
- #ํ๋ก ํธ์๋
- #์์กด์ฑ
- #ํจ์ํ
- #React
์๋ ํ์ธ์. ํ๋กฌ ํ๋ก ํธ์๋ ํ์์ ํ ์คํธ์ ์ด๊ฒ์ ๊ฒ ์ ๋ํ๋ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ๊นํํฌ์ ๋๋ค.
์ ๊ฐ 4์์ ๋ค์ด์๋๋ฐ. ์ด์ 2023๋ ์ด ๋๋๊ณ 2024๋ ์ด ๋ค๊ฐ์ค๊ณ ์์ต๋๋ค. ์ ๊ฐ ๊ณผ๊ฑฐ์ ์งฐ๋ ์ฝ๋๋ ๋ ๊ฑฐ์๊ฐ ๋์ด๊ฐ๊ณ ์. ํ๋ ๋ ์ถ๊ฐํ๋ ๊ธฐ๋ฅ์ ๋ณต์กํ๊ณ ๊ฑฐ๋ํ ๋ก์ง์ด ๋๊ธฐ๋ ํ์ต๋๋ค. ์๋ฒ/๋ธ๋ผ์ฐ์ /webview ๊ฐ์ ๋ค์ํ ํ๊ฒฝ๊ณผ, react์ qwik ๊ฐ์ด ์ฌ๋ฌ ํ๋ ์์ํฌ ๋ฑ์ ์ง์ํ๋ ค ํ๋ฉด์, ์์กด์ฑ์ ๋ํด ์ฌ๋ฌ๋ชจ๋ก ๊ณ ๋ฏผ์ ํ๊ฒ ๋์์ต๋๋ค.
์ด๋ฒ์๋ ๋ชจ๋ ๋ฆฌ์กํธ์ฒ๋ผ ํจ์ํ์ ์งํฅํ๋ ํ๋ก ํธ์๋ ํ๋ ์์ํฌ์์, ์ด๋ป๊ฒ ์์กด์ฑ์ ์ ์ดํ ์ง์ ๋ํด ์ด์ผ๊ธฐํด๋ณด๋ ค ํฉ๋๋ค. ์์กด์ฑ์ ์ง์ ๊ฐ๋ฅํ ์ํํธ์จ์ด ํ๋ก์ ํธ๋ฅผ ์ํด ์ ๋ง ์ค์ํ ์ฃผ์ ์ธ๋ฐ์. class ๊ธฐ๋ฐ ๊ฐ์ฒด์งํฅ์ ํ๋ ๋ฐฑ์๋ ์ํ๊ณ์ ๋ฌ๋ฆฌ, ํ๋ก ํธ์๋์์๋ ์ด๋ ค์ํ๋ ๋ถ๋ค์ด ๋ง์ต๋๋ค.
๊ทธ๋ฌ๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ์์กด์ฑ์ ๋ ์ ์ ์ดํด์ ๋ ์ดํดํ๊ธฐ ์ฝ๊ณ , ๋ณ๊ฒฝํ๊ธฐ ์ฌ์ฐ๋ฉฐ, ์์ ํ ์ฝ๋๋ฅผ ๋ง๋ค ์ ์์์ง ๊ฐ์ด ๊ณ ๋ฏผํด๋ณด์์ฃ .
์์กด์ฑ์ ๋ํ์ฌ
์ฝ์นญ์ ํ๊ณ ํ์ ๋ถ๋ค๊ณผ ์ด์ผ๊ธฐ๋ฅผ ํ๋ค๋ณด๋ฉด ์์กด์ฑ์ ๋ํด ๋ค๋ค ๋ค๋ฅธ ์๊ฐ์ ๊ฐ์ง๊ณ ๊ณ์ญ๋๋ค. ๋ช ํํ์ง ์๊ณ ์ด๊ฒ์ ๊ฒ ์๊ฐ์ด ํผ์ฌ๋ ๊ฒฝ์ฐ๋ ๋ง๊ณ ์. ์ ๋ ์ด๋ฏธ ๊ฐ์ธ ๋ธ๋ก๊ทธ์ ํ๋ฐํธ์๋์์ ์์กด์ฑ์ ์ ์ดํ๋ ๋ฒ์ด๋ผ๋ ๊ธ์ ์ด ์ ์ด ์์ต๋๋ค๋ง.
์ ์ ๊ทธ๋ ํ๋ ์ด์ผ๊ธฐ๋ฅผ ์ ๋ฆฌํด๋ณด๊ณ , ์์กด์ฑ์ ๊ฐ๋ ์ ์ก๊ณ ์์ํด๋ณด๋ ค ํฉ๋๋ค.
์ผ๋จ ์์กด์ฑ์ด๋ผ ํ๋ฉด js๊ฐ๋ฐ์์๊ฒ๋ package.json
์์ dependencies๋ผ ๋ถ๋ฅด๋ ์ธ๋ถ ํจํค์ง
๋ค์ด ๋ ์ค๋ฅด์ค ๊ฒ๋๋ค. ์๋ฅผ ๋ค์๋ฉด react
๋ next
๋ถํฐ jotai
๋ react-query
๊ฐ์ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋, styled-component
๋ tailwind
๊ฐ์ ์คํ์ผ๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ์ด ์๊ฒ ์ต๋๋ค. ์ด๋ฐ ์ธ๋ถ ์์กด์ฑ์ ์ง์ ๋ฐํด๋ฅผ ์ฌ๋ฐ๋ช
ํ ํ์ ์์ด, ๋น ๋ฅด๊ฒ ์ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๊ฒ ๋์์ฃผ๊ธฐ ๋๋ฌธ์ ๋ง์ด๋ค ์ฌ์ฉํฉ๋๋ค.
์ธ๋ถ ์์กด์ฑ์ด ์ ๋ถ๋ ์๋์ง๋ง, ์ผ๋จ ์ธ๋ถ ์์กด์ฑ์ ์ง์คํด๋ณด์ฃ . ๋จผ์ ๊ณต๊ฐ ์ธํฐํ์ด์ค
์ ๋ด๋ถ ๊ตฌํ
์ด ๋ฌด์์ธ์ง ์ดํด๋ด
์๋ค.
์ธํฐํ์ด์ค vs ๋ด๋ถ ๊ตฌํ, ์ ๊ณต์ vs ์ฌ์ฉ์
์ด๋ฐ ์์กด์ฑ ์ ๊ณต์
๋ค์ ์ฌ์ฉ์๋ค์ด ์ฌ์ฉํ ์ ์๋ api๋ฅผ ์ ๊ณตํฉ๋๋ค. api๋ผ ํ๋ฉด http ์๋ฒ์ ํต์ ํ๋ ๊ฒ๋ง ์๊ฐํ์๋ ๊ฒฝ์ฐ๋ ์๋๋ฐ์. ๋ ๋๊ฒ ์๊ฐํ๋ฉด ์ด๋ฐ ๊ฒ๋ ๋ค ๊ณต๊ฐ ์ธํฐํ์ด์ค์
๋๋ค. java ๊ฐ์ ์ธ์ด์์๋ public
์ ๊ทผ ์ ์ด์๋ก, golang ๊ฐ์ ์ธ์ด์์๋ ์ฒซ ๊ธ์๋ฅผ ๋๋ฌธ์๋ก ์ค์ ํ๊ธฐ๋ ํ๋๋ฐ์. javascript ๋ชจ๋์์๋ export
ํ ๊ฒ๋ค์ด ๊ณต๊ฐ ์ธํฐํ์ด์ค์
๋๋ค. ์ด๋ฅผ ์์กด์ฑ ์ฌ์ฉ์
๋ค์ import
ํด์ ์ฌ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด ๋ค์ ์ฝ๋์์๋ jotai๊ฐ ์ ๊ณตํ๋ atom
์ผ๋ก cartAtom
์ ๋ง๋ค๊ณ ์. useAtomValue
๋ก atom์ ํด๋นํ๋ ์ํ๋ฅผ store์์ ๊บผ๋ด์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
// atom/cart.ts
import { atom } from 'jotai';
import { CartVo } from 'vo/shared/Cart.vo';
const cartAtom = atom<CartVo | undefined>(undefined);
export { cartAtom }
// pages/index.tsx
import { useAtomValue } from 'jotai';
import { cartAtom } from 'atom/cart';
function Page(){
const cart = useAtomValue(cartAtom)
// ...
}
์ด๋ ๊ฒ ์๊ฐํ๋ฉด ์ ํฌ๊ฐ ์ง์ ๋ง๋ ์์กด์ฑ๋ ๋น์ทํ๊ฒ ์๊ฐํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด atom/cart.ts
๋ชจ๋์ ์ธ๋ถ์ cartAtom์ ๊ณต๊ฐํ๊ณ ์์ต๋๋ค. pages/index.tsx
๋ชจ๋์์๋ ์ด๋ฐ cartAtom์ ๊ฐ์ ธ๋ค๊ฐ, jotai
์ useAtomValue์ ํจ๊ป ์ฌ์ฉํ๊ณ ์์ฃ .
๋ฆฌํฉํฐ๋ง vs ํ๊ดด์ ๋ณ๊ฒฝ
์ธํฐํ์ด์ค์ ๋์์ ์ ์งํ๋ฉด์ ๋ด๋ถ ๊ตฌํ๋ง ๋ฐ๊พธ๋ฉด ๋ฆฌํฉํฐ๋ง
์ด๋ผ ํฉ๋๋ค. ๊ตฌํ์ ๋ฐ๊พธ๋ฉด์ ์ธํฐํ์ด์ค๊ฐ ๋ฐ๋๊ฑฐ๋, ๊ฒ๋ณด๊ธฐ ๋์์ด ๊นจ์ง๋ฉด ํ๊ดด์ ๋ณ๊ฒฝ
์ด๋ผ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด ๋ฆฌ์กํธ ์ฟผ๋ฆฌ๋ฅผ ์ด์ฉํ ๋ค์ ์ฝ๋๋ฅผ ๋ด์ฃผ์์ฃ . ๋ธ๋๋์ ๊ฒฝ๋ก๋ฅผ ๋ฐ์์, ํด๋นํ๋ ๋ธ๋๋์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง์ธ๋ฐ์. react query v3์์๋ cache key์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋น๋๊ธฐ ํจ์, options๋ฅผ 3๊ฐ์ ์ธ์๋ก ๋ฐ๊ฒ ํ์ต๋๋ค.
import { getBrand } from 'api/brand';
import useOnApiError from 'hooks/useOnApiError';
import { useSuspendedQuery } from 'hooks/useQuery';
const useGetBrand = (brandPath: string) => {
const onApiError = useOnApiError();
return useQuery(
['getBrand', brandPath], // key
(signal) => getBrand(brandPath, signal), // data๋ฅผ ๊ฐ์ ธ์ค๋ ๋น๋๊ธฐ ํจ์
{ onError: onApiError } // options
);
};
export default useGetBrand;
semantic version
์ ์ค์ํ๋ ์์กด์ฑ ์ ๊ณต์๋ค์ minor ๋ฒ์ ์
๋ฐ์ดํธ์์๋ ๋ณดํต ์ธํฐํ์ด์ค ํ์ ํธํ
์ ์งํค๋ ค ๋
ธ๋ ฅํฉ๋๋ค. ์๋ฅผ ๋ค์ด 3.1์์ 3.2๋ก ์ฌ๋ผ๊ฐ๋ฉด์ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์ฌ๋ฌ ๋ด๋ถ ๊ตฌํ์ ๊ฐ์ ํ๋ค๊ณ ํด๋ด
์๋ค. ๊ทธ๋์ ์ธํฐํ์ด์ค๋ ๋ณํ ๊ฒ ์๊ธฐ ๋๋ฌธ์, ์์กด์ฑ์ ์ฌ์ฉํ๋ ํ๋ก์ ํธ์์๋ ๋ฒ์ ์ ์ฌ๋ ค๋ ์๋ฌด ๊ฒ๋ ๊นจ์ง์ง ์์์ผ ํฉ๋๋ค. (๋ฌผ๋ก ์ฑ๋ฅ์ ์ข์์ง๊ฒ ์ฃ .)
์ด๋ ๊ฒ ์ธ๋ถ ์ธํฐํ์ด์ค๋ฅผ ์ ์งํ๋ฉด์, ๋ด๋ถ ๊ตฌํ์ ๊ฐ์ ํ๋ ๊ฒ๋ง ๋ฆฌํฉํฐ๋ง์ด๋ผ ํฉ๋๋ค. ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ์์ผ๋ฉด ๋ค ๋ฆฌํฉํฐ๋ง์ด๋ผ๊ณ ์๋ชป ์ฐ์ด๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ง๋ง์.
์์กด์ฑ ์ ๊ณต์๋ค์ ๋ฉ์ด์ ๋ฒ์ ์ ์ฌ๋ฆด ๋ ํ๊ดด์ ๋ณ๊ฒฝ์ ๋์ ํ๊ธฐ๋ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด react-query๋ฅผ ์ฐ๋ค๋ณด๋ฉด useQuery ๋ง๊ณ ๋ prefetch๋ ๋ค์ํ ๊ธฐ๋ฅ์ key, ๋น๋๊ธฐ ํจ์, options๋ฅผ ๋ณต๋ถํ๊ฒ ๋ ๋๊ฐ ๋ง์๋ฐ์. ๊ทธ๋์ react-query v5์์๋ ์ ์ธ ๊ฐ์ง ์ธ์๋ฅผ ํ๋์ ๊ฐ์ฒด๋ก ๋ฐ๋๋ก ์์ ํ์ต๋๋ค. ๋ฌผ๋ก ์ฝ๊ฐ ๋ ์ฅํฉํด์ง๊ธด ํ์ง๋ง, query ๊ฐ์ฒด๋ฅผ ํ๋ ๋ง๋ค์ด๋๋ฉด ์ด๊ณณ์ ๊ณณ ๊ณต์ ํด์ ์ธ ์ ์์ด์ ํธ๋ฆฌํด์ก์ฃ .
ํ์ง๋ง ์ด๋ ํ๊ดด์ ๋ณ๊ฒฝ์ ๋๋ค! version 5๋ก ์ฌ๋ผ๊ฐ๋ ค๋ฉด ์๋ก์ด ์ธํฐํ์ด์ค์ ๋ง์ถฐ์, ๊ธฐ์กด ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ๋ ๊ฑฐ์ ์ฝ๋๋ฅผ ๋ฏ์ด๊ณ ์ณ์ผ ํฉ๋๋ค. ์ด๋ฐ ๊ณณ์ด 28๊ณณ์ด๋ผ๋ฉด? 100๊ณณ์ด๋ผ๋ฉด? 1000๊ณณ์ด๋ผ๋ฉด?
๊ทธ๋ฆฌ๊ณ ๋ณ์๋ช ์ด๋ ๋งค๊ฐ๋ณ์ ๋ชจ์์ด ๋ฐ๋๋ ์ ๋๊ฐ ์๋๋ผ ํจ๋ฌ๋ค์์ด ๋ฐ๋๋ ์์ค์ ํฐ ํ๊ดด์ ๋ณ๊ฒฝ๋ ์์ต๋๋ค.
- react๊ฐ class component์ life cycle์์ hook์ผ๋ก ๊ฐ์ํ๋ฉด์ ๋ชจ๋ ์ํ๊ณ๊ฐ ๋ค์งํ์ต๋๋ค
- react์ server component๊ฐ ๋์ ๋๋ฉด์ styled๋ emotion ๋ฑ์ ๊ธฐ์กด css in js ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋์ํ์ง ์๊ฒ ๋์์ต๋๋ค
- react-query๋ v5๋ถํฐ useQuery์ onSuccess๋ onError ๋ฑ์ handler๋ฅผ ์ ๊ณตํ์ง ์๊ธฐ๋ก ํ์ต๋๋ค
์คํ ํ๊ฒฝ๊ณผ ํ์ค, ์ด๋ํฐ, ํด๋ฆฌํ
์ ํฌ๋ ๋ค์ํ ์คํ ํ๊ฒฝ(runtime)
์์ ์ฝ๋๋ฅผ ๋๋ฆฝ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ์๋ ๊ณผ๊ฑฐ Netscape ๋ธ๋ผ์ฐ์ ์์ ๋์๊ฐ๊ธฐ ์ํด ๋ง๋ค์ด์ง ์ธ์ด์์ต๋๋ค. ์ธํฐ๋ท ์ต์คํ๋ก๋ฌ๊ฐ ์ธ์์ ์ง๋ฐฐํ๊ณ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ฒ ๊ปด์ JScript๋ฅผ ๋ง๋ค๊ธฐ๋ ํ๊ณ ์. ๊ทธ ํ์ ๋์จ ํฌ๋กฌ์ด๋ ํ์ด์ดํญ์ค ๋ฑ ๋ค์ํ ๋ธ๋ผ์ฐ์ ๋ค๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ง์ํ์ต๋๋ค๋ง. ํ์ค
์ด ์์ด๋ ๋ง์ดํฌ๋ก์ํํธ๊ฐ ๋ฌด์ํ๊ณ ์ด๋ฐ์ ๋ฐ ๋ณต์กํ ์ญ์ฌ๊ฐ ์์์ต๋๋ค.
์ฌ๋ฌ ์์กด์ฑ๋ค์ด ๊ฐ์์ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค์ด์ ๋๋ฆฝํ๊ฒ ๋๋ฉด, ์์กด์ฑ ์ฌ์ฉ์๋ค์ ๊ณ ํต ๋ฐ๊ฒ ๋ฉ๋๋ค. ๋ง์น C ํ์ ์ถฉ์ ๊ธฐ๋ฅผ ์ฐ์ง ์๋ ์ ํ ๋ง๋ฅ. ์์กด์ฑ ์ฌ์ฉ์๋ค์ ๋ค์ํ ํ๊ฒฝ๊ณผ ๋ค์ํ ์์กด์ฑ์ ์ธํฐํ์ด์ค๋ฅผ ์ง์ํ๊ธฐ ์ํด์ ๋จธ๋ฆฌ๋ฅผ ์ธ๋งค๊ฒ ๋ฉ๋๋ค. ์ด๋ ์ง๊ธ๋ ํ์ฌ ์งํํ์ด๋ผ ํฌ๋กฌ์์๋ ์ ๋์๊ฐ๋๋ฐ ์ฌํ๋ฆฌ์์๋ ์ ๋์๊ฐ๋ค๋ ์ฌ์ฉ์ ๋ฌธ์๋ฅผ ๋ฐ์ ๋๋ง๋ค, ๊ฐ๋ฐ์๋ค์ ๋๋ฌผ์ ํ๋ฆฌ์ฃ . ์๋ก ๋์จ css ๊ธฐ๋ฅ์ ์ฐ๊ธฐ ์ ์๋ ๋งค๋ฒ can i use ๊ฐ์ ์ฌ์ดํธ์ ๋ธ๋ผ์ฐ์ ์ง์ ๋ฒ์๋ฅผ ๊ฒ์ํด๋ณด๊ณ ์.
์ด๋ฐ ์คํ ํ๊ฒฝ๋ค์ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ํ ์ค๋ ๊ณ ์น์ง ์์๋ ์์์ ๋ณํํฉ๋๋ค. ์ฌํ๋ฆฌ 16์์๋ ์ ๋๋ ์ฝ๋๊ฐ ์ฌํ๋ฆฌ 17์์๋ ๋ณด์์ด ๊ฐํ๋๋ฉด์ ๊นจ์ง๊ธฐ๋ ํ๊ณ ์. ์ฌํ๋ฆฌ 17์ ๋์จ ๊ธฐ๋ฅ์ ์จ๋ณด๋ ค ํด๋ ์ฌํ๋ฆฌ 14๋ฅผ ์ฐ๋ ์ฌ์ฉ์๋ค์ ์ง์ํ ์ ์์ด์ ํฌ๊ธฐํ๊ธฐ๋ ํฉ๋๋ค. ์๋๋ก์ด๋๋ ios๋ ์๋ก ๋ฒ์ ์ ์ ํ๊ณ , js๋ ๊ณ์ํด์ ES6, ES2023, ES2024๊ฐ ๋์ต๋๋ค.
๊ทธ๋์ ์ด๋ค ์์กด์ฑ์ ์ธํฐํ์ด์ค๋ฅผ ๋ค๋ฅธ ์์กด์ฑ์ ์ธํฐํ์ด์ค๋ก ๋ณํํด์ฃผ๋ ์ด๋ํฐ
๋ค์ด ๋์ต๋๋ค. Java๋ ๋๊ฐ์ ์ฝ๋๊ฐ window, linux, mac์์ ๋ชจ๋ ๋์๊ฐ ์ ์๊ฒ ํด์คฌ์ฃ . JQuery๋ ๋น์ผ๊ด์ ์ธ ๋ธ๋ผ์ฐ์ js ์ฌ์ด์์ ์ผ๊ด๋ ๋ฐฉ์์ผ๋ก dom์ ์กฐ์ํ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ์ต๋๋ค.
ํํธ ์ ๋ฒ์ ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌ ๋ฒ์ ์ ๊ธฐ๋ฅ๋ง์ผ๋ก ๋น์ทํ๊ฒ ๊ตฌํํด์ฃผ๋ ํด๋ฆฌํ
๋ ๋ง์ด๋ค ์ฌ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด core-js
์ babel/preset-env
๋ browserlist
์ ์ ๋ณด๋ฅผ ์ด์ฉํด์ ์์์ ๊ตฌ๋ฒ์ ์ js๋ก ๋ณํํด์ฃผ๊ฑฐ๋, ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ api๋ ๋น์ทํ๊ฒ ๋ง๋ค์ด์ ๋ฃ์ด์ค๋๋ค. ๋ชจ๋ css๋ฅผ ์ ๋ธ๋ผ์ฐ์ ์์ ๋์๊ฐ๊ฒ ํด์ฃผ๋ postcss-preset-env
๊ฐ์ ๊ฒ๋ ์์ต๋๋ค.
์ง๊ธ๊น์ง ์ ๋ฆฌํ ๊ฐ๋ ๋ค์ ํ ๋ฒ ๋์ง์ด ๋ณด์์ฃ . ๋ด๊ฐ ์ฝ๋ฉ์ ํ๋ฉด์ ๊ฒช์๋ ์ฌ๋ก๋ ๋ ์ฌ๋ ค๋ณด์ ๋ค์ ๊ณ์ ์ฝ์ด๋๊ฐ์๋ฉด ์ข๊ฒ ์ต๋๋ค.
์์กด์ฑ์ ํ๊ดด์ ๋ณ๊ฒฝ์ ๋์ฒํ๊ธฐ
์์ ์ด์ผ๊ธฐํ ๊ฒ์ฒ๋ผ ์ธ๋ถ ์์กด์ฑ์ ์ธํฐํ์ด์ค๋ฅผ ๊ณณ๊ณณ์์ ์ง์ importํด์ ์ฌ์ฉํ๋ฉด, ํ๊ดด์ ๋ณ๊ฒฝ์ด ์ผ์ด๋ฌ์ ๋ ๊ณ ์น ๋ถ๋ถ์ด ๋ง์์ง๋๋ค. ๋๋ฌด ๋ง์ ์ฌ์ฉ์๊ฐ ์ด ์ธํฐํ์ด์ค์ ์์กดํ๊ณ ์๊ธฐ ๋๋ฌธ์ด์ฃ . ์ธ๋ถ ์์กด์ฑ์ด๋ผ๋ฉด ๋ฒ์ ์ ์ฌ๋ฆฌ์ง ์๊ณ ๋ฒํธ ์๋ ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ ์์กด์ฑ์ด๋ผ๋ฉด ํ์ ํธํ์ ์ ์งํ๋ ค ํ ์๋ ์๊ณ ์.
ํ์ง๋ง ์ํ๊ณ์ ๋ฐํ์์ด ๋ฐ์ ํ๋ ๊ฑด ๋ง์ ์ ์์ต๋๋ค. ์ ๊ฐ ์๋ ์ด๋ค ํ๋ก์ ํธ๋ ํ์ด์ฌ ๋ฒ์ ์ ์ฌ๋ฆฌ์ง ์๊ณ ๋ฒํฐ๋ค๊ฐ, ํฌ๋งคํฐ๋ ๋ฆฐํธ ๊ฐ์ ๋ชจ๋ ํด๊น์ง ์ง์์ด ๋๊ธฐ๋ฉด์ ๋ฒ์ ์ ์ฌ๋ฆด ์ ๋ฐ์ ์๊ฒ ๋์์ต๋๋ค. react class component๋ก ๋ ๋ ๊ฑฐ์๋ค๋ ๋น์ทํ ์ ์ธ์ ์ฒํด ์์ฃ .
๊ทธ๋ฌ๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ์ข์๊น์?
์ธ๋ถ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ์ธ๊ธฐ
๋จผ์ ์ธ๋ถ ์์กด์ฑ์ ํ ๋ฒ ์ค๊ฐ ๊ณ์ธต์ ๋์ด์ ๊ฐ์ธ๋(wrap) ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ํ๋ก๋ํธ ์ฝ๋์์๋ ์ธ๋ถ ์์กด์ฑ์ ์ง์ importํ ์ ์๊ฒ ๋ง์ผ๋ฉด ๋ฉ๋๋ค. ๊ทธ๋์ ๊ฐ์ฒด์งํฅ ์ชฝ ์ฑ
์ ๋ณด์๋ฉด ๊ทธ๋์ ์ธ๋ถ ์์กด์ฑ์ ์ง์ ์์กดํ์ง ๋ง๋ผ๊ณ ํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์์ ํ ์ธํฐํ์ด์ค๋ก ํ ๋ฒ ๊ฐ์ธ๋๊ณ , ์ธ๋ถ ์์กด์ฑ์ ์ด์ฉํด์ ๋ด๋ถ๋ง ๊ตฌํํ๋ ๊ฒ์ด์ฃ . ์ด๋ฅผ โ์ถ์ํ์ ์์กดํ๊ณ ๊ตฌํ์ ์์กดํ์ง ์๋๋คโ๊ณ ๋ ํ๊ณ ์. ์ ์ํ? ๋ง๋ก๋ ์ ์ด์ ์ญ์
์ด๋ผ๊ณ ๋ ๋ถ๋ฆ
๋๋ค.
์ด๋ ํนํ ์์กด์ฑ์ด ๋ณ๊ฒฝ๋ ๊ฐ๋ฅ์ฑ์ด ๋๊ฑฐ๋, ๋ง์ ๊ณณ์์ ์ฌ์ฉํ ์์ ์ด๋ผ๋ฉด, ํน์ ๋ค์ํ ๊ตฌํ์ฒด๋ก ๋น๋ํ ํ์๊ฐ ์์ ๋์๋ ๊ผญ ์งํค์๋ฉด ์ข์ต๋๋ค.
์์กด์ฑ ์ฃผ์ ์ ๋ํด ๊ฒ์ํด๋ณด๋ฉด ์ธ์์ ์๋ฐ์ ์์ฑ์ ์ฃผ์ ๊ณผ setter ์ฃผ์ ๋ง ์๋ ๊ฒ์ฒ๋ผ ์ค๋ช ํ๊ณ , ์์ฑ์ ์ฃผ์ ์ด ๋ ์ข๋ค๋ ์ค๋ช ๋ง ๋ณต์ฌ ๋ถ์ฌ๋ฃ๊ธฐ ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์๋๋ฉด @๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋จ๋ฐํ ์คํ๋ง ์ ์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ๋ง ๋ง์ด ๋์ค๋๋ฐ์.
ํ์ง๋ง react๋ ํ๋ก ํธ์๋์์๋ class๋ interface๋ฅผ ์ฐ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ํจ์์์๋ ์ด๋ป๊ฒ ํ๋ฉด ์ข์๊น์?
๋ฆฌ์กํธ์์๋ ๋ณดํต ์ปค์คํ ํ ์ด๋ ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์์์ ๋ณธ cartAtom์ ๋ค์์ฒ๋ผ useCart๋ก ๊ฐ์ ์ ์์ต๋๋ค.
// atom/cart.ts
import { atom, useAtom } from 'jotai';
import { CartVo } from 'vo/shared/Cart.vo';
const cartAtom = atom<CartVo | undefined>(undefined);
function useCart(){
return useAtom(cartAtom)
}
export { cartAtom, useCart }
// pages/index.tsx
import { useCart } from 'atom/cart';
function Page(){
const [cart] = useCart()
// ...
}
์ด๋ ๊ฒ ํ๋ฉด atom/cart
๋ง jotai์ ์์กดํ๊ณ ์, pages/index.tsx
๋ jotai์ ์กด์ฌ๋ฅผ ๋ชจ๋ฅด๊ฒ ๋ฉ๋๋ค. ํน์๋ jotai ๋ง๊ณ react-query๋ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๊ฐ์ํ๊ฒ ๋๋๋ผ๋ useCart
์ ๊ตฌํ๋ง ์์ ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
ํํธ ๊ธฐ์กด์ useQuery๋ฅผ useQueryRequest
๋ผ๋ ์ด๋ฆ์ผ๋ก ์ด๋ฏธ ๊ฐ์ธ์ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค. ์์ ๋งํ ๋ถํธํจ๋ ์๊ณ , cacheKey์ ์ธ์ด๋ ํตํ ๊ฐ์ ์์ฃผ ๊ฒน์น๋ ์์๋ฅผ ๋งค๋ฒ ๋ฃ์ด์ฃผ๊ธฐ๊ฐ ๋ฒ๊ฑฐ๋ก์์ ๋ง๋ ๊ฒ์ด์๋๋ฐ์. ์ด๋ฒ์ react-query v5๋ก ์ฌ๋ผ๊ฐ๋ฉด์ ํ๊ดด์ ๋ณ๊ฒฝ์ด ์๋นํ์ง๋ง, useQueryRequest
๋ ์ด๋ฏธ ๊ฐ์ฒด ํ๋๋ง ๋ฐ๋๋ก ํด๋์ด์ ๋ด๋ถ ๊ตฌํ๋ง ๊ณ ์ณ์ฃผ๋ฉด ๋์์ต๋๋ค.
์ธ๋ถ ์์กด์ฑ์ ์ ์ฐํ๊ฒ migrationํ๊ธฐ
์์กด์ฑ์ ์ฌ์ฉํ๋ค๋ณด๋ฉด ์ฐ๋ฆฌ๊ฐ ์ง์ํด์ผํ๋ ํ๊ฒฝ์์๋ ๋์ํ์ง ์์์, ์ด์ฌ(migration)๋ฅผ ๊ฐ์ผํ ๋๊ฐ ์์ต๋๋ค.
์ ํฌ๋ ์ค์ ๋ก jotai์ SSR ๋์์ด ์ ํฌ๊ฐ ๊ธฐ๋ํ๋ ๊ฒ๊ณผ ๋ฌ๋ผ์ currencyAtom
์ cookie์ useSyncExtenralStore๋ก migration ํ ์ ์ด ์์๋๋ฐ์. ์ฌํ๊ฒ๋ useAtom(currencyAtom)
์ ๊ณณ๊ณณ์์ ์ฐ๊ณ ์์ด์, ๋ชจ๋ ์ฝ๋๋ฅผ ์์ ํด์ผ ํ์ต๋๋ค.
๋ ๋ค๋ฅธ ์์๋ก tailwind๋ styled component ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋์์ธ ์์คํ ์ด๋ ๊ณต์ฉ ์ปดํฌ๋ํธ๋ก ํ ๋ฒ ๊ฐ์ธ๋๋ฉด ์ข์ต๋๋ค. ์ด๋ฌ๋ฉด ์ฌ์ฉํ๊ธฐ์๋ ํธ๋ฆฌํ๊ณ ์. styled-component ๋ฑ์ ์ฌ์ฉํ ์ ์๋ server-component ๋ฑ์ผ๋ก migration์ ํ ๋ ๊ณต์ฉ ์ปดํฌ๋ํธ์ ์คํ์ผ๋ง ๋๊ฐ์ด ๋ง๋ค์ด์ฃผ๋ฉด ๋๊ฑฐ๋ ์. ํ๋ก์ ํธ ์ ๋ฐ์ ๋ณต์ฌ ๋ถ์ฌ๋ฃ๊ธฐํ ์คํ์ผ์ด ํผ์ ธ์๋ค๋ฉด, ํ ์คํ์ผ์์ ๋ค๋ฅธ ์คํ์ผ๋ก ๋ฐ๊พธ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ค์ธ ๊ฒ๋๋ค.
๋น์ทํ๊ฒ react-router-dom
์ ์ฌ์ฉํ๋ ๋ถ๋ค์ next/router
๋ก ๊ฐ์ํ๋ฉด์ ์ฌ๋ฌ๊ฐ์ง ๊ณ ํต์ ๊ฒช๊ฒ ๋์ค ๊ฒ๋๋ค. Link
๋ useRouter
๊ฐ์ ๊ฑธ ํ ๋ฒ ๊ฐ์ธ๋์๋ค๋ฉดโฆ <Link to="..."
๊ฐ <Link href="..."
๋ก ๋ฐ๋๋ ์์ ์ฌ์ํ ์ฐจ์ด์ ๋ ์ฝ๊ฒ ๋์ํ ์ ์์ ๊ฒ๋๋ค. storybook์ด๋ test ํ๊ฒฝ์ฒ๋ผ Next router๋ฅผ ์ฌ์ฉํ ์ ์๋ ํ๊ฒฝ์์๋ next์ ๋ด๋ถ ๊ตฌํ๊ณผ ์จ๋ฆํ ํ์ ์์ด, ๊ตฌํ์ฒด๋ง ๋ฐ๊พธ๋ฉด ๋์ง์.
์ด๋ฐ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ๋์๋ ํ์ค์ ๋ํด ๊น์ด ์๊ฐํด๋ณด์๋ฉด ์ข์ต๋๋ค. ์๋ฅผ ๋ค์ด router
๋ฅผ ์ถ์ํํ๋ ค๋ฉด โreact-router-domโ, โnextโ, โstackflowโ ๋ฑ, ์ฐ๋ฆฌ๊ฐ migrationํ ๊ฐ๋ฅ์ฑ์ด ๋์ ๊ตฌํ์ฒด๋ค์ ์ดํด๋ณด์๊ณ ๊ณตํต์ ์ ๋ฌด์์ด๊ณ ์ฐจ์ด์ ์ ๋ฌด์์ธ์ง ๊ณ ๋ฏผํด๋ณด์๋ฉด ์ข์ต๋๋ค.
์์กด์ฑ์ ๋ช ์์ ์ผ๋ก ๋๋ฌ๋ด๊ณ ์ฃผ์ ํ์
๋ค์์ผ๋ก ์ธ๋ถ ์์กด์ฑ์ด ์๋ ์์ ํจ์๋ฅผ ๋ถ๋ฆฌํ๊ณ , ์ธ๋ถ ์์กด์ฑ์ ๋ช
์์ ์ผ๋ก ๋งค๊ฐ๋ณ์๋ก ๋๊ธฐ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. component์์๋ prop
์ผ๋ก ๋๊ธฐ๋ ๊ฒ์ด ์ฌ๊ธฐ์ ํด๋นํ๊ณ ์. class ๊ธฐ๋ฐ ๊ฐ์ฒด์งํฅ์์๋ ์์ฑ์ ์ฃผ์
๋ฐฉ์๋ ์ด์ ์ ์ฌํฉ๋๋ค. ์ด๋ ํนํ ๋ค์ํ ํ๊ฒฝ์ ์ง์ํ๋ ์ฝ๋๋ฅผ ๋ง๋ค๊ฑฐ๋, ๋ณต์กํ๊ณ ์ค์ํ ํต์ฌ ๋ก์ง์ ๋ง๋ค ๋ ์ ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด ๋ค์ useFormatPrice ํ ์ ์ฌ์ฉ์๊ฐ ์ค์ ํ currency์ lang์ context์์ ์์์ ์ผ๋ก ๊ฐ์ ธ์ค๊ณ ์์ต๋๋ค. ๊ทธ๋์ ํ์ฌ ์ฌ์ฉ์๊ฐ ์ค์ ํ ํตํ์ ์ธ์ด๋ก ๊ฐ๊ฒฉ์ ๋ ๋ํด์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
export const useFormatPrice = () => {
const { lang } = useTranslation('common');
const currency = useCurrencyValue();
const formatPrice = useCallback(
(price: number | null, lang: LanguageCodeT, currencyCode = currency.code) => {
const formattedPrice = addCommaToNumber(price ?? 0);
if (currencyCode === 'KRW') {
return lang === 'ko' ? `${formattedPrice}์` : `โฉ${formattedPrice}`;
}
// currentCode === 'USD'
return `$${formattedPrice}`;
},
[currency.code, lang]
);
return { formatPrice };
};
const { formatPrice } = useFormatPrice()
// ์ฌ์ฉ์๊ฐ KRW, ko๋ก ์ค์ ํ ๊ฒฝ์ฐ
formatPrice(1000) // 1000์
// ์ฌ์ฉ์๊ฐ KRW, en์ผ๋ก ์ค์ ํ ๊ฒฝ์ฐ
formatPrice(1000) // โฉ1000
// ์ฌ์ฉ์๊ฐ USD๋ก ์ค์ ํ ๊ฒฝ์ฐ
formatPrice(1000) // $1000
ํํ๋ค ๋ง๋๋ ํ ์ด๊ณ ๋น์ฅ์ ํธ๋ฆฌํด๋ณด์ด์ง๋ง ์ฌ๋ฌ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
๋จผ์ react hook์ ์์กดํ๊ธฐ ๋๋ฌธ์ server component์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด hook์ ์ด์ฉํ๋ ์ปดํฌ๋ํธ๋ ๋ง์ฐฌ๊ฐ์ง๊ณ ์. ์ ํฌ๋ ์ธ์ด๋ ํตํ๋ ์๋ฒ์์ url๊ณผ cookie๋ก ์ ์ ์๋๋ฐ, ์ฌ์ฉ์ ๋ชปํ๊ฒ ๋ฉ๋๋ค.
๋ค์์ผ๋ก ์ฌ์ฉ์๊ฐ ์ค์ ํ ํตํ์ ๋ค๋ฅด๊ฒ ๋ ๋ํ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ์ฌ์ฉํ ์๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์ด๋ค ํ๊ตญ์ธ ์ฌ์ฉ์๊ฐ 61000์์ ์จ๋ฒ์ ์๋ค๊ณ ํด๋ด ์๋ค. ๋ฏธ๊ตญ์ ์ฌ๋ ์น๊ตฌ์๊ฒ๋ ์จ๋ฒ์ ์ฌ์ฃผ๋ ค๊ณ USD๋ก ์ค์ ํ ๋ค์, ์ฃผ๋ฌธ ๋ด์ญ์ ๋ค์ด๊ฐ๋ฉด ๋ค์์ฒ๋ผ ์ด์ํ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
61,000์์ด ์๋๋ผ, ํ์ฌ ์ค์ ๋ ๋ฌ๋ฌ๋ก ๊ฐ๊ฒฉ์ด ๋ค๋ฅด๊ฒ ํ๊ธฐ๋๋ ๊ฒ์ด์ฃ ! ์ธ๋ถ์์ formatPrice๋ฅผ ์ ์ดํ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค. formatPrice๋ ์ฌ์ฉ์๊ฐ ์ค์ ํ ์ธ์ด์ ํตํ๋ ๋ฌผ๋ก ์ด๊ณ react hook๊ณผ ๊ฐ๊ฒฐํฉ๋์ด ์์ด์ ์ ์ฐํ์ง ๋ชปํ ์ฝ๋๊ฐ ๋์์ต๋๋ค.
๊ทธ๋ฌ๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ์ข์๊น์? formatPrice๋ฅผ ์์ ํจ์๋ก ๋ถ๋ฆฌํ๊ณ , ๋งค๊ฐ๋ณ์๋ก context๋ฅผ ๋๊ธฐ๋ฉด ๋ฉ๋๋ค.
function formatPrice(price: number | null, currencyCode: CurrencyCodeT, lang: LanguageCodeT){
const formattedPrice = addCommaToNumber(price ?? 0);
if (currencyCode === 'KRW') {
return lang === 'ko' ? `${formattedPrice}์` : `โฉ${formattedPrice}`;
}
// currentCode === 'USD'
return `$${formattedPrice}`;
}
// ์ฌ์ฉ์๊ฐ KRW, ko๋ก ์ค์ ํ ๊ฒฝ์ฐ
formatPrice(1000, 'KRW', 'ko') // 1000์
// ์ฌ์ฉ์๊ฐ KRW, en์ผ๋ก ์ค์ ํ ๊ฒฝ์ฐ
formatPrice(1000, 'KRW', 'en') // โฉ1000
// ์ฌ์ฉ์๊ฐ USD๋ก ์ค์ ํ ๊ฒฝ์ฐ
formatPrice(1000, 'USD', 'ko') // $1000
์ด๋ฌํ ์์กด์ฑ์ renderHook
์ด๋ Provider
๋ก ๊ฐ์ธ์ฃผ๋ ๊ฒ์ฒ๋ผ ๋ฆฌ์กํธ์ ํน์ํ ๋ก์ง ์์ด ์ ์ฝ๊ฒ ํ
์คํธํ ์ ์์ต๋๋ค. qwik ๊ฐ์ ๋ค๋ฅธ ํ๋ ์์ํฌ์์๋ ์ฌ์ฉํ ์ ์๊ณ ์.
ํ์ง๋ง ์ด๋ฌ๋ฉด ๋งค๋ฒ ๋งค๊ฐ๋ณ์๋ก 3๊ฐ์ฉ ๋๊ฒจ์ผ ํ๋ ๋ฒ๊ฑฐ๋กญ์ต๋๋ค. ๊ทธ๋์ context์ ์์กด์ฑ์ ์ฃผ์ ํด์ค custom hook์ ๋ง๋ค ์ ์์ต๋๋ค.
export const useFormatPrice = () => {
const { lang } = useTranslation('common');
const currency = useCurrencyValue();
return {
formatPrice: (price: number | null, currencyCode = currency.code, lang = lang) => formatPrice(price, currencyCode, lang)
};
};
const { formatPrice } = useFormatPrice();
formatPrice(1000) // 1000์
formatPrice(1000, 'USD') // $1000
์ด๋ ๊ฒ ํน์ ๋งค๊ฐ๋ณ์๋ฅผ ์ฑ์๋ ์๋ก์ด ํจ์๋ฅผ ๋ง๋๋ ๊ธฐ๋ฒ์ ํจ์ํ์์๋ ๋ถ๋ถ ์ ์ฉ
ํน์ ์ปค๋ง
์ด๋ผ๊ณ ๋ ๋ถ๋ฆ
๋๋ค.
์์กด์ฑ์ด ์๋ ์์ ํจ์๋ ์๋ฒ์์๋ ๋ธ๋ผ์ฐ์ ์์๋ ์ ๋์๊ฐ๋๋ค. ์ด๋ ์ฌ๋ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๋ ๋น์ทํ ์ ๋ต์ ์ฐ๊ณ ์์ผ๋ ์ฐธ๊ณ ํด๋ณด์๋ฉด ์ข์ต๋๋ค.
component์ prop์ ๋ช ์์ ์ผ๋ก ์ฃผ์ ํ๊ธฐ
๋น์ทํ๊ฒ ์ปดํฌ๋ํธ๋ ์์ ํจ์๋ก ๋ง๋ค๊ณ props๋ฅผ ์ด์ฉํด ๋ช
์์ ์ผ๋ก ์์กด์ฑ์ ๋๊ธฐ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. props๋ ํจ์์ ๋งค๊ฐ๋ณ์์ผ ๋ฟ์ด๋๊น์. (class ๊ฐ์ฒด์งํฅ์์๋ ์์ฑ์ ์ฃผ์
์ด๋ผ๊ณ ๋ ๋ถ๋ฆ
๋๋ค.) ๊ณผ๊ฑฐ์๋ props๋ฅผ ์ด์ฉํด ์์กด์ฑ์ ์ฃผ์
ํ๋ ๊ฒ ๋น์ฐํ ๋ฐฉ๋ฒ์ด์์ต๋๋ค. ๊ทธ ๋น์์๋ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํด์ ์ปดํฌ๋ํธ์ ํน์ props๋ฅผ ๋ถ๋ถ ์ ์ฉํ์ง์. ์์์ ๋งํ ๋ถ๋ถ ์ ์ฉ๊ณผ ๋ค๋ฅด์ง ์์ต๋๋ค. ์ง๊ธ๋ next-translate
๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ hook์ ์ด์ฉํ ๋ฐฉ๋ฒ๊ณผ ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํ ๋ฐฉ๋ฒ์ ๋ ๋ค ์ง์ํ๊ณ ์์ต๋๋ค.
import React from 'react'
import withTranslation from 'next-translate/withTranslation'
class ErrorBoundary extends React.Component {
render() {
const { t, lang } = this.props.i18n
return <p>{t('common:error-title')}</p> // <p>์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค!</p>
}
}
export default withTranslation(ErrorBoundary)
๊ทธ๋ฐ๋ฐ hook์ด ๋์ค๊ณ ๋์๋ props์ ํ์ ์ ์ ์ํ๊ณ , ๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๊ฒ ๋ฒ๊ฑฐ๋กญ๊ธฐ๋ ํ๊ณ ์. hook์ import๋ง ํ๋ฉด ์ฝ๊ฒ ๊ฐ์ ธ๋ค ์ฐ๊ณ ํฉ์ฑํ ์ ์์ผ๋, ์ ์ props๋ฅผ ์ด์ฉํ ์ฃผ์ ๋ฐฉ์์ด ์ํ์ ธ ๊ฐ๊ณ ์์์ต๋๋ค๋งโฆ
server side rendering์ด ๋์ค๋ฉด์ ์ด์ผ๊ธฐ๊ฐ ์ข ๋ฌ๋ผ์ง๊ธฐ ์์ํ์ต๋๋ค. nextjs์ pages ๋ผ์ฐํฐ๋ฅผ ์ฌ์ฉํด๋ณด์ ๋ถ๋ค์ ์์๊ฒ ์ง๋ง, getServerSideProps๋ฅผ ์ด์ฉํด์ Page์ ์๋ฒ์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ ์ฃผ์ ํฉ๋๋ค. ์๋ฒ ์ปดํฌ๋ํธ์์๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ props์ ์ด์ฉํด์ ๋ช ์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ฃผ๊ณ ์. ๋ง์ฝ์ props๋ฅผ ๋ฐ์ง ์๊ณ , ํน์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ hook์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๊ฑฐ๋ผ๊ณ ๊ฐ์ ํ๋ค๋ฉด ์ด๋ฐ ๋ณํ์ ์ ์ํ๊ธฐ๊ฐ ์ด๋ ค์ธ ๊ฒ๋๋ค.
๊ทธ๋ฌ๋ hook์ ์ฐ์ง ๋ง์๋ ๊ฒ์ ์๋๋๋ค๋ง. (์ ๋ props๋ฅผ ์ด์ฉํ ์ฃผ์ ์ ์์ ํ๋ ํธ์ ๋๋ค.) props๋ฅผ ์ด์ฉํ ์ฃผ์ ๋ฐฉ์์ด ๋ฒ๊ฑฐ๋ก์๋ณด์ผ์ง๋ผ๋, ์ข์ ๋์ ์ค ํ๋๋ผ๋ ๊ฑธ ๊ธฐ์ตํด์ฃผ์๋ฉด ์ข๊ฒ ์ต๋๋ค.
ํ์ํ ๊ณณ์๋ง ์์กดํ๊ธฐ aka ์ธํฐํ์ด์ค ๊ฒฉ๋ฆฌ์ ์์น
๋งค๊ฐ๋ณ์๋ ํ์ํ ๊ฒ๋ง ๋ฐ๊ณ , ์๋ก ๋ค๋ฅธ ๋ก์ง์ ์ธํฐํ์ด์ค๋ ๋ถ๋ฆฌํ๋ ๊ฒ ์ข์ต๋๋ค.
ํจ์๋ ์ปค์คํ ํ ์ ๋ง๋ค๋ค๋ณด๋ฉด ๊ฑฐ๋ํ ํ์ ์ ๋ง๋ค๊ณ , ํ์ ์์กด์ฑ์ ์ด๊ณณ์ ๊ณณ์ ํผํธ๋ฆฌ๊ณ ๋ ํฉ๋๋ค. ์ด๋ฌ๋ฉด ๊ฒฐํฉ๋๋ ๋์์ง๊ณ , ํ ์คํธ๋, ์ฌ์ฉ๋ ์ด๋ ค์์ง๋๋ค.
์๋ฅผ ๋ค์ด ์ ํฌ ํ์๋ ์ํ์ ์ํ๋ฅผ ํ์ ํ๋ ์ฝ๋๊ฐ ์๋๋ฐ์. ์ํ์ ๋ฑ ํ์ํ ๋ฐ์ดํฐ 4๊ฐ์๋ง ์์กด์ ํ๊ฒ ๋์ด ์์ต๋๋ค.
import type { GoodsStatusT } from 'Types';
export type ComputedGoodsStatusT = 'ready' | 'soldout' | 'quit' | 'comingsoon';
export function computeGoodsStatus(
{
startDate,
endDate,
status
}: {
startDate?: number; // ํ๋งค ์์ ์๊ฐ
endDate?: number; // ํ๋งค ์ข
๋ฃ ์๊ฐ
status?: GoodsStatusT; // ์๋ฒ์์ ์ง์ ํ ์ํ ์ํ
},
now: number
): ComputedGoodsStatusT {
// ์ดํ ๋ก์ง
}
๊ทธ๋ฐ๋ฐ ์ฝ๋๋ฆฌ๋ทฐ๋ฅผ ํ๋ค๋ณด๋ฉด, api์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ Type ์ ์์ ๋ค ์ง์ด ๋ฃ๋ ๊ฒฝ์ฐ๋ฅผ ๋ณด๊ณ ๋ ํฉ๋๋ค. ๋น์ฅ์ ํธ๋ฆฌํ๊ณ ๊ฐ๊ฒฐํด๋ณด์ ๋๋ค.
import type { GoodsStatusT } from 'Types';
import type { GetGoodsResponse } from '@knowmerce/store-api-goods';
export type ComputedGoodsStatusT = 'ready' | 'soldout' | 'quit' | 'comingsoon';
export function computeGoodsStatus(
{
startDate,
endDate,
status
}: GetGoodsResponse, // <- api์์ ๊ฐ์ ธ์จ ํ์
์ ๊ทธ๋๋ก ๋ฃ์์ต๋๋ค.
now: number
): ComputedGoodsStatusT {
// ... ์ดํ ์๋ต
}
ํ์ง๋ง ์ด๋ฌ๋ฉด computeGoodsStatus๋ GetGoodsReponse์๋ง ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ ํฌ๋ ์ํ์ ์ ํํ๊ฒ ๋์์ฃผ๋ Bundle์ด๋ผ๋ ๊ฒ ์๋๋ฐ์. Bundle์๋ startDate, endDate, status๊ฐ ๋ค ์๊ณ ๋ก์ง๋ ๋๊ฐ์ต๋๋ค. (๋๊ฐ์์ผ ํฉ๋๋ค) ๊ทธ๋ฐ๋ฐ ์ด๋ฌ๋ฉด bundle์ ์ํ ๋ก์ง์ ์๋ก ๋ณต์ฌ ๋ถ์ฌ๋ฃ๊ธฐํด์ ๋ง๋ค์ด์ผ ํ์ฃ .
ํ ์คํธ๋ ์ด๋ ค์์ง๋๋ค. ์๋ ์ด ์์ ํจ์๋ ๋งค๊ฐ ๋ณ์๊ฐ ๋ช ๊ฐ ๋์ง ์์ผ๋, ๋ค์์ฒ๋ผ ์ฝ๊ฒ ํ ์คํธํ ์ ์์์ต๋๋ค.
const ์์์ = unixDate(2019, 12, 31, 23, 59);
const startDate = unixDate(2020, 1, 1);
test('startDate ์ด์ ์ด๋ฉด, comingsoon ์ด๋ค', () => {
expect(computeGoodsStatus({ status: 'ready', startDate }, ์์์ )).toBe('comingsoon');
});
ํ์ง๋ง ์ด์ ๋ ๊ฐ์ฒด๋ฅผ ํต์งธ๋ก ๋ง๋ค์ด์ ๋๊ฒจ์ค์ผ ํฉ๋๋ค. ์ํ์ด ํ๋งค ์ค์ธ์ง๋ฅผ ํ๋จํ๋ ๊ฒ๊ณผ ๋ฌด๊ดํ ์ํ ์ด๋ฆ์ด๋ ์ค๋ช , ์ด๋ฏธ์ง ๋ฑ๋ฑ์ ์ ๋ถ ๊ฐ์ง๋ก ๋ง๋ค์ด์ผ ํ์ฃ . ๋ง์ฝ์ api์ ์๋ก์ด ํ๋๊ฐ ์ถ๊ฐ๋๊ฑฐ๋, ๋ฐฑ์๋์์ ํ๋๋ช ์ ๋ฐ๊พธ๊ฒ ๋๋ค๋ฉด ๋ก์ง๋ ํ ์คํธ๋ ๊ณ ์ณ์ผํ ๊ฒ์ ๋๋ค.
test('startDate ์ด์ ์ด๋ฉด, comingsoon ์ด๋ค', () => {
expect(computeGoodsStatus({
status: 'ready',
startDate,
id: 333,
name: '๋๋ฆผ์บ์ณ (Dreamcatcher) 8th Mini Album [Apocalypse : From us] [W ver.] (ํ์ ๋ฐ)',
description: '...์ํ ์ค๋ช
...',
body: '๋งค์ฐ ๊ธด ์ํ ์์ธ ์ค๋ช
',
image: 'https://my-awesome-domain/images/333/f0ca6dc0-2494-406b-8250-8c4bd03d76f2_1683775448296',
// ... ์ดํ ์๋ต
}, ์์์ )).toBe('comingsoon');
});
์ ์ด๋ ๊ฒ ๋์์๊น์? ์ด ํจ์๋ฅผ ์ฌ์ฉํ๋ ์ฌ์ฉ์์๊ฒ ๋๋ฌด ๋ง์ ๊ฑธ ์๊ตฌํ์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ํต์ ํ ์ ์๋ ์๋ฒ์ ํ์ ์ ๊ฐ๊ฒฐํฉ๋์๊ณ ์. ์ฐ๋ฆฌ์ ๊ด์ฌ์ฌ์ ๋ฌด๊ดํ ์ธํฐํ์ด์ค๋ฅผ ๋ค์์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฌธ์ ์ ํด๊ฒฐ์ฑ ์ ๊ฐ๋จํฉ๋๋ค. ์ธํฐํ์ด์ค ์ฌ์ฉ์์๊ฒ ์ต์ํ๋ง ์๊ตฌํ๊ณ , ์๋ก ๋ค๋ฅธ ์ธํฐํ์ด์ค๋ฅผ ๋ค์์ง ์์ผ๋ฉด ๋ฉ๋๋ค. ๊ท์ฐฎ๋๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ๋ถ๋ฆฌํ์๊ณ ์์ ํ์ ์ ์ฌ๋ฌ ๊ฐ ๋ง๋์๋ ๊ฒ ์ข์ต๋๋ค.
context๋ฅผ ์ด์ฉํ ์์กด์ฑ ์ฃผ์
๋ง์ง๋ง์ผ๋ก context์ ๋ชจ๋์ ๋ํ ์ด์ผ๊ธฐ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค.
๋ง์ ๋ถ๋ค์ด react์ context api๋ฅผ ๋ฆฌ๋์ค ๊ฐ์ ์ํ ๊ด๋ฆฌ ๋๊ตฌ๋ก๋ง ์คํดํ์๊ณ ๋ ํ๋๋ฐ์. ๊ทธ๋ ๋ค๊ณ ํ๋ฉด ์ข ์ด์ํ ๊ฒ ๋ง์ต๋๋ค. ๋ค๋ค ์ด์ผ๊ธฐํ์ง๋ง ๋ฆฌ๋ ๋๋ ์ต์ ํ๋์ง ์๊ณ ์. redux๋ jotai ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ์ด ์จ์ผ ํฉ๋๋ค.
jotai ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ Provider๊ฐ ํ์ ์๋ Provider less ๋ชจ๋๋ฅผ ์ง์ํ๊ธฐ๋ ํ๊ณ ์. ์ ์ญ singleton ๊ฐ์ฒด๋ฅผ ์ด์ฉํด์ ๋น์ทํ ๊ธฐ๋ฅ์ ์ง์ํ๋ ๊ฒฝ์ฐ๋ ๋ง์ต๋๋ค.
context api๊ฐ ์ ๋ง ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ์๊ฐํด๋ณด๋ฉด ๊ผญ ๊ทธ๋ด ํ์๋ ์์ต๋๋ค. ๋๋ถ๋ถ์ ๊ฑฐ์ ๋ณํ์ง ์๋ ์ ์ ์ธ ๊ฒ๋ค๋ง ๊ตฌ๋ ํฉ๋๋ค.
ํนํ props์ ์ด์ฉํ ์์กด์ฑ ์ฃผ์ ์ด ๋ฒ๊ฑฐ๋กญ๊ณ , ์ปดํฌ๋ํธ ๊ณ์ธต์ ๋๋๋ค๋ฉด์ ์์กด์ฑ์ ์ฃผ์ ํด์ผ ํ ๋ ํธ๋ฆฌํ ๋๊ตฌ์ง์. ์์ ์ด์ผ๊ธฐํ ๊ฒ์ฒ๋ผ props์ ์ด์ฉํด์ ์์กด์ฑ ์ฃผ์ ์ ํ๋ค๋ณด๋ฉด ๋ฒ๊ฑฐ๋ก์ฐ์ค ๋๊ฐ ๋ง์ํ ๋ฐ์. ๊ทธ๋ฐ props ๋ด๋ฆฌ๊ธฐ ๋ฌธ์ ๋ ์ฌ์ค ๊ฐ์ฒด์งํฅ์ด๋ ๋ฐฑ์๋์์๋ ๋ ์๋ ์ผ์ด๊ณ , ๋ค๋ค ์์กด์ฑ ์ฃผ์ ๋ฌธ์ ๋ผ๊ณ ์๊ฐํฉ๋๋ค. (์์ฑ์์ ์์ฑ์์ ์์ฑ์โฆ)
๋ค๋ฅธ ํ๋ ์์ํฌ๋ฅผ ์จ๋ณด์ ๋ถ์ ์์๊ฒ ์ง๋ง, context api๋ ์์กด์ฑ ์ฃผ์ ๋๊ตฌ๋ก ๋ง์ด ์ฐ์ ๋๋ค. context api์ ์ ์ฌํ ๊ธฐ๋ฅ์ vue์์๋ provide / inject๋ผ ๋ถ๋ฆ ๋๋ค. svelte๋ getContext์ setContext๋ผ๊ณ ํ๊ณ ์. ์๋ฒ ํ๋ ์์ํฌ๋ค์์๋ context๊ฐ db connection์ด๋ ๋ก๊ทธ์ธํ ์ ๋ณด ๊ฐ์ ์ธ๋ถ ์์กด์ฑ์ ๋ค๊ณ ์์ต๋๋ค.
vue์์ ์ฐ๋ ์ฉ์ด๊ฐ ํนํ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ผ๋ง ํฉ๋๋ค. inject
? ํด๋์ค ๊ฐ์ฒด์งํฅ ์ธ์ด์์ ์์กด์ฑ ์ฃผ์
(Dependency Injection)์ ํด๋ณด์ ๋ถ์ ์์๊ฒ ์ง๋ง, ์์กด์ฑ์ โ์ฃผ์
โํ๋ค๋ ๋ง์
๋๋ค.
react์์๋ context api๋ ๋ณดํต ์์กด์ฑ์ ์ฃผ์ ํ๋ ์ฉ๋๋ก ์๋๋ค. redux๋ jotai ๊ฐ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ store๋ฅผ context api๋ก ์ฃผ์ ํ๊ณ ์ฌ์ฉํฉ๋๋ค. react-router-dom์ Provider๋ฅผ ์ด์ฉํด ๊ตฌํ์ฒด๋ฅผ ๊ฐ์ ๋ผ์ธ ์ ์์์ต๋๋ค. (MemoryRouter, HashRouter ๊ฐ์) tanstack-query๋ QueryClient๋ฅผ context๋ก ์ฃผ์ ํฉ๋๋ค. ๊ทธ๋์ test๋ฅผ ์ํด ๊ฐ์ง ์์กด์ฑ์ ์ฃผ์ ํ ๋์๋ ์ด๋ฐ Provider๋ฅผ ์ฌ์ฉํ์ฃ .
context API๋ ์ด๋ฑํ ๋ฆฌ๋์ค๊ฐ ์๋๋๋ค. context๋ ์์ฃผ ๋ณํ๋ ์ํ๋ณด๋ค๋, ์ฌ์ฉ์ ์ค์ ์ด๋ ํ ๋ง, ์์์ ๋งํ ๊ฒ์ฒ๋ผ ์์ฃผ ๋ณํ์ง ์๋ ์์กด์ฑ์ธ ๊ฒฝ์ฐ๊ฐ ๋ ๋ง์ต๋๋ค.
์๋ฅผ ๋ค์ด์ ์์ ์์์์ ์ ๋ currency๋ lang์ component์ props๋ก ๋ฐ์ง ์๊ณ , useCurrencyValue
๋ useTranslation
๊ฐ์ ํ
์ ์ด์ฉํด์ ๋ฐ์๋๋ฐ์. ์ด ์ญ์ ์ผ์ข
์ context๋ฅผ ์ฃผ์
๋ฐ์๋ค๊ณ ํ ์ ์๊ฒ ์ต๋๋ค.
// props๋ก ์ฃผ์
function Component({ currency, lang }: { currency: CurrencyCodeT, lang: LanguageCodeT })
// Context๋ก ์ฃผ์
function Component()
const { lang } = useTranslation('common');
const currency = useCurrencyValue();
context ์ฃผ์
์ ์ฝ๊ฒ ํฉ์ฑํ ์ ์๊ณ , ๋งค๋ฒ ํ์
์ ์์ฑํ ํ์๋ ์์ด์ ํธ๋ฆฌํฉ๋๋ค๋ง. react ํ๊ฒฝ์์๋ง ์ธ ์ ์์ด, qwik ๊ฐ์ ๋ค๋ฅธ ํ๋ ์์ํฌ๋ getServerSideProps
์ฒ๋ผ ๋ค๋ฅธ ํ๊ฒฝ๊ณผ ๋ก์ง์ ๊ณต์ ํ์ง ๋ชปํฉ๋๋ค. ๊ทธ๋์ ์ ๋ ๋ณดํต ์์ํ ๋ก์ง์ ๋ง๋ค๊ณ , react ํ๊ฒฝ์ ํน์ํ ์์กด์ฑ์ context๋ก ์ฃผ์
๋ฐ๋ hook์ ๋ง๋ค์ด ์ฌ์ฉํ๋ ํธ์
๋๋ค.
module alias์ importmap์ ์ด์ฉํ ์์กด์ฑ ์ฃผ์
๊ทธ๋ฐ๋ฐ ๋ฆฌ์กํธ ํ์ Sebastian์ Context๋ฅผ ์ด์ฉํ ๋ฐํ์ ์์กด์ฑ ์ฃผ์
๋ณด๋ค๋ ์ ์ ์ธ module alias๋ฅผ ๋ ์ ํธํ๋ค๊ณ ํฉ๋๋ค. ์ฌ์ง์ด Runtime dependency injection is the worst thing ever
๋ผ๊ณ ๊ฐ๋ ๋๊ฒ ๋นํํ ์ ๋์ธ๋ฐ์. ํนํ subtree๋ง๋ค ๋ค๋ฅธ ์์กด์ฑ์ ์ฃผ์
ํด์ฃผ๋ ๊ฒ ์๋๋ผ, ์ฑ ์ ์ฒด์ ์ ์ญ ์์กด์ฑ์ ์ฃผ์
ํ๋ ๊ฒฝ์ฐ์๋ ํนํ ๊ทธ๋ ๋ค๊ณ ํฉ๋๋ค.
๊ทธ ์ด์ ๋ ์ดํด๊ฐ ๊ฐ๋๋ค. ๋ฐํ์ ์์กด์ฑ ์ฃผ์ ์ ์ฑ๋ฅ์์ผ๋ก ๋๋ฆฌ๊ณ ์. ์ฑ ์ด๊ธฐํ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ฒ ํฉ๋๋ค. ์คํ๋ง์ด๋ ๋ค์คํธ๋ก ๋ฐฑ์๋ ๊ฐ๋ฐ์ ํด๋ณด์ ๋ถ์ ๊ณต๊ฐํ์์ง ์์๊น ์ถ๋ค์ ^^ ๋ณ๊ฒฝ๋์ง ์๋ ์์กด์ฑ์ด๋ผ๋ฉด ํนํ ์ ์ ์ผ๋ก ๋งํฌํ๋ ๊ฒ ์ข๊ณ , ๋์ ์ผ๋ก ์ฃผ์ ํ๋ ๊ฑด ๋์ฑ ๋นํจ์จ์ ์ ๋๋ค.
๊ทธ๋ ๋ค๋ฉด sebastian์ด ์ ์ํ๋ ๋์์ธ ์ ์ ์ธ module alias
๋ ๋ฌด์์ผ๊น์? webpack์ด๋ vite ๊ฐ์ ๋ฒ๋ค๋ฌ์ module alias ๊ธฐ๋ฅ์ ์ด์ฉํ๋ฉด ํน์ ๋ชจ๋์ importํ๋ ์ฝ๋๋ฅผ ์ฝ๊ฒ ๋ฐ๊ฟ์น๊ธฐ ํ ์ ์์ต๋๋ค. ๋ณดํต์ js์์ ์ ๋ ๊ฒฝ๋ก import๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ์ฐ์ด๊ณ ๋ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด next๋ก ๊ฐ๋ฐํ๋ค๋ณด๋ฉด, vitest๋ storybook ๊ฐ์ ํ
์คํธ ํ๊ฒฝ์์ next/link
๋ next/image
๋ฑ์ด ์๋ํ์ง ์๊ณ ๋ ํ์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ณดํต ์ด๋ฌํ ํ๊ฒฝ์ mockingํ๋ ค๊ณ ๊ณ ์ํ๊ฒ ๋๋๋ฐ์. laddle์ด๋ผ๋ ์คํ ๋ฆฌ๋ถ ๋์ฒด ํ๋ ์์ํฌ์ ๋ฌธ์์์๋ ๋ ๋จ์ํ ๋ฐฉ๋ฒ์ ์ ์ํฉ๋๋ค. ํ
์คํธ๋ฅผ ์ํ ๊ฐ์ง ๊ตฌํ์ฒด๋ก next์์ importํ๋ ๋ชจ๋์ ๋ฐ๊ฟ์น๊ธฐํ๋ ๊ฒ์ด์ฃ .
import path from "path";
import { defineConfig } from "vite";
export default defineConfig({
resolve: {
alias: {
"next/image": path.resolve(__dirname, "./.ladle/UnoptimizedImage.tsx"),
"next/link": path.resolve(__dirname, "./.ladle/UnoptimizedLink.tsx"),
},
},
});
const UnoptimizedLink = (props: any) => {
return <a {...props} />;
};
export default UnoptimizedLink;
const UnoptimizedImage = (props: any) => {
return <img {...props} />;
};
export default UnoptimizedImage;
์ด ๋ฐฉ๋ฒ์ ํ ์คํธ๋ฅผ ์ํด์๋ ์ ์ฉํ์ง๋ง, ๋ค์ํ ํ๊ฒฝ์ ์ง์ํด์ผ ํ๋ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ๋์๋ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ ๋ ํ๋์ ์ฝ๋๋ฒ ์ด์ค๋ก ์น๊ณผ ๋ฐ์คํฌํ ์ฑ(tauri), ๋ชจ๋ฐ์ผ ์ฑ(capacitor)์ ๋ชจ๋ ์ง์ํ๋ ํ๋ก์ ํธ๋ฅผ ๋ง๋ ์ ์๋๋ฐ์. vite.config๋ฅผ 3๊ฐ ๋ง๋ค์ด์ ๊ฐ ํ๊ฒฝ๋ง๋ค ๋ค๋ฅธ ์์กด์ฑ์ ์ฃผ์ ํด์ ๋น๋ํ๋๋ก ํ์์ต๋๋ค.
์์ ๋งํ ๊ฒ ๊ฐ์ ๊ธฐ์ ์คํ์ migration ํ๋ ์ํฉ์๋ ์ ์ฉํฉ๋๋ค. ๊ธฐ์กด์ ์์กด์ฑ๊ณผ ์ธํฐํ์ด์ค๊ฐ ํธํ๋๋ ์ด๋ํฐ๋ฅผ ๋ง๋์ ๋ค์, module alias๋ก ์ฒ๋ฆฌํ์๋ฉด ๊ธฐ์กด ์ฝ๋๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ ๋ ์ ๊ธฐ์ ์คํ์ผ๋ก ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ๋ง์ด๊ทธ๋ ์ด์ ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด react์ ๋ ๊ฐ๋ฒผ์ด ๊ตฌํ์ฒด์ธ preact๊ฐ ์๋๋ฐ์. preact ๋ฌธ์์์๋ preact/compat
์ด๋ผ๋ ํธํ ๋ชจ๋๋ก aliasํด์ ๊ธฐ์กด react ํ๋ก์ ํธ๋ฅผ ํต์งธ๋ก migrationํ๋ ๋ฒ์ ์๋ ค์ค๋๋ค. ๋ค์ํ ๋ฒ๋ค๋ฌ์์ module alias๋ฅผ ํ๋ ๋ฐฉ๋ฒ์ ์น์ ํ ์ค๋ช
ํด์ฃผ๊ณ ์์ผ๋, webpack์ด๋ vite ๊ฐ ์๋ ๋ฒ๋ค๋ฌ๋ฅผ ์ฐ์๋ ํ์์๋ ์ฐธ๊ณ ํด๋ณด์๋ฉด ์ข๊ฒ ์ต๋๋ค.
const config = {
//...snip
"resolve": {
"alias": {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat", // Must be below test-utils
"react/jsx-runtime": "preact/jsx-runtime"
},
}
}
๊ทธ๋ฌ๋ฉด ์ด๋ฐ module alias๋ ๋ฒ๋ค๋ฌ๋ฅผ ์ฌ์ฉํด์ผ๋ง ์ธ ์ ์์๊น์? ์๋ก ๋์จ importmap
์ ๋ธ๋ผ์ฐ์ ๊ฐ module์ resolveํ๋ ๋ฐฉ๋ฒ์ ์ง์ ํ๋ ํ์ค์
๋๋ค. ๋ฒ๋ค๋ฌ๋ฅผ ์ฌ์ฉํ์ง ์๋ ํ๋ก์ ํธ์์๋ ์ฝ๊ฒ module alias๋ฅผ ์ค์ ํ๊ณ , ์ฌ๋ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ฝ๊ฒ importํ ์ ์์ต๋๋ค. js ๋ฐฑ์๋ ์ํ๊ณ์์๋ deno ๊ฐ์ ๋ฐํ์๋ค๋ ์ ์ง์ํด์ฃผ๊ณ ์์ต๋๋ค.
ํ์ง๋ง module alias๋ ํ๊ณ๊ฐ ์๋ ๋ฐฉ๋ฒ์ด๊ธฐ๋ ํฉ๋๋ค. react๋ก server side rendering์ ํ๋ค๋ณด๋ฉด, ์ฌ์ฉ์๋ request๋ง๋ค ์ํ๋ ์์กด์ฑ์ ๊ณต์ ํ๋ฉด ์ ๋๋ ๊ฒฝ์ฐ๋ ์๊ธฐ๊ณ ์. ์ฌ์ฉ์ ์ค์ ์ฒ๋ผ ๋ฐํ์์ ๋ฐ๋๋ ์ํ ์์กด์ฑ๋ ๊ฒฝ์ฐ๋ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. (์์ฃผ ๋ฐ๋์ง๋ ์๊ฒ ์ต๋๋ค๋ง)
์๋ฅผ ๋ค์ด ํ ํ์ด์ง๋ KRW๋ก ๋ ๋๋๋๋ผ๋, ๋ค๋ฅธ ํ์ด์ง๋ USD๋ก ๋ ๋ํ๊ณ ์ถ์ ์ ์๋๋ฐ์. react-query๋ jotai ๋ฑ์ ๋ฌธ์๋ฅผ ๋ณด์๋ฉด ๋ณดํต ๋ฐํ์์ QueryClient๋ store๋ฅผ request๋ง๋ค ๋์ ์ผ๋ก ๋ง๋ค์ด์ ํด๊ฒฐํฉ๋๋ค.
import { Hydrate, QueryClient, QueryClientProvider } from 'react-query'
// query client๋ฅผ ์ ์ ์ผ๋ก ์์ฑํ๋ฉด ๋ชจ๋ ์ฌ์ฉ์๊ฐ query๋ฅผ ๊ณต์ ํ๊ฒ ๋ฉ๋๋ค X
// const queryClient = new QueryClient()
export default function MyApp({ Component, pageProps }) {
// ๋ฐํ์์ ๋์ ์ผ๋ก ์์ฑํ๋ฉด ๋ ๋๋ง๋ค ๊ฒฉ๋ฆฌ๋ฉ๋๋ค O
const [queryClient] = React.useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps.dehydratedState}>
<Component {...pageProps} />
</Hydrate>
</QueryClientProvider>
)
}
์ ํฌ๋ ์ค์ ๋ก ์ด ์ฒ๋ฆฌ๋ฅผ ๊น๋จน์ด์, ํ๋ก๋์ ์์ ์ด์๋ก ์ด์ด์ง ์ ๋ ์์ต๋๋ค. ์์์๋ ์ธ๊ธํ๋ $61000 ์ด์์ธ๋ฐ์. KRW์์ USD๋ก ํตํ ์ค์ ์ ๋ฐ๊พธ์ด๋ ๊ณ์ KRW๋ก ๋ ๋๋์ด์ ์ฌ์ฉ์ ๋ถ๋ค์ด ๋ถํธ์ ๊ฒช์ผ์ จ์ฃ โฆ
์ด ๊ธฐ๋ฒ์ ํ ์คํธ์์ ์ํ๋ฅผ ๊ฒฉ๋ฆฌํ ๋์๋ ํํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค. ๋ฐํ์ ์์กด์ฑ ์ฃผ์ ์ ํ ์ฝ๋๋ ๋งค ํ ์คํธ๋ง๋ค ์ํ๋ฅผ ๋ง๋ค์ด์ ์ฝ๊ฒ ์ฃผ์ ํ๊ณ , ๋ค๋ฅธ ํ ์คํธ์๋ ๊ฒฉ๋ฆฌํ ์ ์์ฃ . ๋๋ถ์ ์ฌ๋ฌ ํ ์คํธ๋ฅผ ๋์(concurrent)์ ๋ณ๋ ฌ(parallel)๋ก ๋๋ ค์ ํ ์คํธ๋ฅผ ๋น ๋ฅด๊ฒ ๋ง๋ค ์๋ ์๊ณ ์. ํ ์คํธ ๋ฌ๋์ ๊ฐ๋น์ผ isolation์ด๋ global ์ ๋ฆฌ์ ์์กดํ์ง ์์์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์ ํฌ์ vitest๋ isolate ์ต์ ์ ๋๋ฉด 2๋ฐฐ ๋นจ๋ผ์ก๊ณ ์. isolation์ ์ง์ํ์ง ์๋ bun test๋ฅผ ์ฐ๋ฉด 157๊ฐ์ typescript unit test๋ฅผ ์คํํ๋๋ฐ 0.1์ด ๋ฐ์ ๊ฑธ๋ฆฌ์ง ์์ต๋๋ค. ์ ์ ์ธ ์์กด์ฑ ์ฃผ์ ์ผ๋ก ์ ์ญ ์ํ๋ฅผ ๊ณต์ ํ๊ฒ ํ๋ค๋ฉด ๋ถ๊ฐ๋ฅํ๊ฒ ์ฃ .
๊ทธ๋ฆฌ๊ณ ์ต๊ทผ JIT ์ปดํ์ผ์ด ์์ฃผ ์ฐ๋ ์ฝ๋๋ inline ์ต์ ํ ๋ฑ์ ํตํด ๋์ ์ธ ์์กด์ฑ ์ฃผ์ ์ ๋น์ฉ์ ์ค์ฌ์ฃผ๊ณ ์์ต๋๋ค. ์ ๋ js ๋ฟ๋ง ์๋๋ผ python์ด๋ lua ๋ฑ์ ์ธ์ด์์ ๋ค์ํ๊ฒ ์คํ์ ํด๋ณด๊ณ ์๋๋ฐ์. ํ๋ฒํ ์ธํฐํ๋ฆฌํฐ์ ๋ฌ๋ฆฌ JIT compile์ ํ๋ ๊ตฌํ์ฒด์์๋ ์ด๊ธฐํ ์ดํ์๋ ํฐ ์ฐจ์ด๊ฐ ์์ด์ ์ ๊ธฐํ๊ฒ ์๊ฐํ๋ ๊ธฐ์ต์ด ์์ต๋๋ค.
๋ชจ๋ ์์กด์ฑ ์ฃผ์
๋ฐฉ๋ฒ์ ๊ฐ์ ์ฅ์ ๊ณผ ํ๊ณ๊ฐ ์์ผ๋, ์ด๋ค ์์กด์ฑ์ ์ด๋ป๊ฒ ๊ด๋ฆฌํ ์ง ๊ณ ๋ฏผํด๋ณด์๋ฉด ์ข๊ฒ ์ต๋๋ค. ํญ์ ์ ์ ์ธ ์์กด์ฑ ์ฃผ์
๋ง ์ฐ๊ฑฐ๋, ํญ์ ๋์ ์ธ ์์กด์ฑ ์ฃผ์
๋ง ์ธ ์๋ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ด๊ฐ ํน์ ์ด์๋ ๋ฌธ์ ๋ก ํฌ๊ฒ ๊ณ ํต ๋ฐ์๋ค๊ณ ํด์, ๊ทธ ๋ฐฉ๋ฒ๋ก ์์ฒด๊ฐ the worst thing ever
๋ผ๊ณ ๋จ์ ์ง์ด์๋ ์ ๋๊ฒ ์ต๋๋ค. ๋ฌผ๋ก ํ๋ช
ํ ์ฌ๋๋ ๊ทธ๋ฐ ์ค์๋ฅผ ํ ๋๊ฐ ์์ง๋ง์.
๊ฒฐ๋ก
์์ง ํ๊ณ ์ถ์ ์ด์ผ๊ธฐ๊ฐ ๋ง์ง๋ง, ์์ฝ๊ฒ๋ ์ด๋ฏธ ์ด์ผ๊ธฐ๊ฐ ๋ง์ด ๊ธธ์ด์ ธ์ ์ด๋ง ์ค์ฌ์ผํ ๊ฒ ๊ฐ์ต๋๋ค. ์ง๊ธ๊น์ง ํ ์ด์ผ๊ธฐ๋ฅผ ์ถ์์ ์ผ๋ก ์์ฝํด๋ณผํ ๋, ๊ตฌ์ฒด์ ์์๋ค์ ๋ ์ฌ๋ ค๋ณด์๋ฉด์ ์ฒ์ฒํ ์ฝ์ด๋ณด์์ฃ .
์ ํฌ๋ ์์กด์ฑ์
์ ๊ณต
ํ๊ธฐ๋ ํ๊ณ์ฌ์ฉ
ํ๊ธฐ๋ ํฉ๋๋ค. ์์กด์ฑ์๊ณต๊ฐ ์ธํฐํ์ด์ค
๋ฅผ ์ด์ด๋๊ณํธํ์ฑ
์ ์ฝ์ํ๋ฉฐ๋ด๋ถ ๊ตฌํ
์๋ฆฌํฉํฐ๋ง
์ ํด๋๊ฐ๋๋ค. ํ์ง๋ง ์ฌํ๊ฒ๋ ์ธํฐํ์ด์ค์ ํ๊ณ๋ฅผ ๋ง๋๋ฉดํ๊ดด์ ๋ณ๊ฒฝ
์ ๋ง๋ค๋ฉด์ ๋ฉ์ด์ ๋ฒ์ ์ ์ฌ๋ฆฌ๊ธฐ๋ ํฉ๋๋ค.ํ๊ดด์ ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ฉด ์ฌ์ฉ์๋ค์ ์ฝ๋๋ฅผ ๋๋์ผ๋ก ์์ ํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๊ณ ํต์ค๋ฌ์์ง๋๋ค. ๊ทธ๋์ ๋ณดํต์ ์ฐ๋ฆฌ๊ฐ ์์ ํ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํด์
์ถ์
์ ์์กดํ์ง, ํน์ ๊ตฌํ์ ์์กดํ์ง ์๋๋ก์ ์ด์ ์ญ์
์ ํด์ ์ฌ์ฉํฉ๋๋ค. ์ธ๋ถ ์์กด์ฑ์ ๊ฐ์ธ๋์ด๋ํฐ
๋ฅผ ๋ง๋ค์ด์ ์ฐ๋ฆฌ์ ์ธํฐํ์ด์ค์ ๋ง์ถ๋๋ก ํ๊ณค ํฉ๋๋ค.class ๊ธฐ๋ฐ ๊ฐ์ฒด์งํฅ ์ํ๊ณ์ ๋ฌ๋ฆฌ, ํจ์ ์ํ๊ณ์์๋ ์ฃผ๋ก
์์ ํจ์
๋ฅผ ์ด์ฉํฉ๋๋ค. ์์กด์ฑ์ด ์๊ณ ์์ธก ๊ฐ๋ฅํ ์์ ํจ์์ ๋ช ์์ ์ผ๋ก ์์กด์ฑ์ ๋๊ธฐ๋ฉด, ์๋ฒ๋ ๋ธ๋ผ์ฐ์ ๊ฐ์ด ๋ค์ํ ํ๊ฒฝ์ ์ฝ๊ฒ ์ง์ํ ์ ์์ต๋๋ค. ํ ์คํธํ๊ธฐ๋ ๋ฌผ๋ก ์ฌ์์ง๊ณ ์. ํ์ง๋ง ๋งค๊ฐ๋ณ์๊ฐ ๋๋ฌด ๋ง์ผ๋ฉด ๋ฒ๊ฑฐ๋กญ๊ธฐ ๋๋ฌธ์, ๋ณดํต์ ์์กด์ฑ์ ๋ฏธ๋ฆฌ๋ถ๋ถ ์ ์ฉ
ํ ํจ์๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํฉ๋๋ค. props๋ฅผ ํตํด ์ปดํฌ๋ํธ์ ์์กด์ฑ์ ์ฃผ์ ํ๋ ๊ฒ๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ด์ฉํ ์ฃผ์ ๊ณผ ๋๊ฐ๊ณ , class์์๋ ์์ฑ์ ์ฃผ์ ๊ณผ ์ ์ฌํ๊ฒ ์๊ฐํ ์ ์์ต๋๋ค.์์กด์ฑ์ ์ธํฐํ์ด์ค๋ฅผ ์ค๊ณํ ๋์๋ ์ฌ์ฉ์์๊ฒ ํ์ํ ์ต์ํ๋ง ์๊ตฌํ๋ ๊ฒ ์ข์ต๋๋ค. ์ฌ๋ฌ ๊ด์ฌ์ฌ๊ฐ ์ธํฐํ์ด์ค์ ๋ค์์ด๋ฉด ๋ค์ํ ํ๊ฒฝ์์ ์ฌ์ฉํ๊ธฐ ์ด๋ ต๊ณ , ํ ์คํธํ๊ธฐ ์ด๋ ค์ด ์ฝ๋๊ฐ ๋ฉ๋๋ค. ์ด๋ฅผ
์ธํฐํ์ด์ค ๊ฒฉ๋ฆฌ์ ์์น
์ด๋ผ๊ณ ๋ ๋ถ๋ฆ ๋๋ค.react์
context API
๋ ์ฃผ๋ก ์ํ ๊ด๋ฆฌ๋ณด๋ค๋ ์์กด์ฑ ์ฃผ์ ๋๊ตฌ๋ก ๋ ๋๋ฆฌ ์ฐ์ ๋๋ค. vue๋ svelte ๊ฐ์ ๋ค๋ฅธ ํ๋ ์์ํฌ๋ ์ ์ฌํ ๋ฐฉ๋ฒ์ ์ง์ํฉ๋๋ค. ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๊ณ ๋๊ธฐ๊ณ ๋ฅผ ๋ฐ๋ณตํ ํ์ ์์ด, ์ปดํฌ๋ํธ tree๋ฅผ ๋ฐ์ด ๋์ด์ ์ฝ๊ฒ context๋ฅผ ์ฃผ์ ํ ์ ์์ต๋๋ค.ํ์ง๋ง ๋ฐํ์ ์์กด์ฑ ์ฃผ์ ์ ๋ฒ๊ฑฐ๋กญ๊ณ , ์ฑ๋ฅ ์ด์๊ฐ ์์ ๋๋ ์์ต๋๋ค. ๋ฒ๋ค๋ฌ๋ ์ ์ ์ผ๋ก
module alias
๋ฅผ ํตํด ๋น๋์์ ์ค์ ํ ์์กด์ฑ๊ณผ ์ฐ๊ฒฐํด์ค๋๋ค. ์ด๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ด์ง๋ง, ๋ฐํ์์ request๋ test๋ง๋ค ์ํ๊ฐ ๊ฒฉ๋ฆฌ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ์๋ ์ฌ์ฉํ๊ธฐ ์ด๋ ต์ต๋๋ค. ์ํฉ์ ๋ฐ๋ผ ์ด๋ค ๋ฐฉ๋ฒ์ด ์ข์์ง๋ ๊ฐ์ธ์ ๊ฒฝํ์ด๋ ์ ์ข์ ๊ธฐ์ต์ด ์๋๋ผ, ์คํ๊ณผ ๋ฒค์น๋งํฌ, ํ๋ก์ ํธ์ ๋งฅ๋ฝ์ ์์ธํ ์ดํผ๊ณ ๊ฒฐ์ ํด์ผ ํฉ๋๋ค.
์ธ์์ ์์กด์ฑ์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ด ์ธ์๋ ๋งค์ฐ ๋ง๊ณ ๋ค์ํฉ๋๋ค. ์์กด์ฑ์ ์์กด์ฑ์ ์ด๊ธฐํํ๋ ์์กด์ฑ ๊ทธ๋ํ๋ผ๊ฑฐ๋, ์์กด์ฑ scope, ์ง์ ์์กด์ฑ์ ํ๋จํด์ ์ ํํ๋ ์์กด์ฑ ์ ํ, event๋ message๋ฅผ ์ด์ฉํด์ ๋์จํ ๊ฒฐํฉ์ผ๋ก ์์กด์ฑ์ ๊ฒฉ๋ฆฌํ๋ ๋ฒ๋ ์๊ณ ์. pandacss๋ tailwind๊ฐ CSS๋ผ๋ ํ์ค์ ์ ์ ์ปดํ์ผ๋ฌ์ ๊ฒฐํฉํด์ ๋ค์ํ ํ๋ ์์ํฌ๋ฅผ ์ง์ํ๋ ๊ฒ๋ ํฅ๋ฏธ๋กญ์ต๋๋ค. ์ต๊ทผ์ SSR์ด ๋์ ๋๊ณ ์๋ฒ์ ํด๋ผ์ด์ธํธ๋ผ๋ ๋ ๊ฐ์ ํ๊ฒฝ์ ์ง์ํ๊ฒ ๋์๋ค๊ฑฐ๋. ์ ํฌ์ฒ๋ผ ๋ค์ํ ํ๋ ์์ํฌ๋ฅผ ์ฐ๋ ํ์์ ๊ณตํต ๋ก์ง์ ๊ด๋ฆฌํ๋ฉด์ ์๊ฐํด๋ณผ ์ ๋ ์ ์ ๋ง์์ง๊ณ ์์ง ์๋ ์ถ์ต๋๋ค. ์ธ์ ๊ฐ ๋จ์ ์ด์ผ๊ธฐ๋ ํ ์ ์๋ ์๊ฐ์ด ์๊ธฐ๊ธธ ๋ฐ๋๋๋ค.
๊ธด ๊ธ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ์ฌ๋ฌ๋ถ์ด ํ๋ก ํธ์๋ ์์กด์ฑ์ ๋ ํ๋๋ฆฌ๊ณ , ๋ ํต์ ๊ถ์ ๊ฐ์ง์ค ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์์ผ๋ก๋ ๋ ๋ค์ํ ์ด์ผ๊ธฐ๋ฅผ ๋ค๊ณ ์ค๊ฒ ์ต๋๋ค. ๋ ๋ต์ฃ .