๐ [Next.js] router.push์ ๋์ ์๋ฆฌ์ ์ฌ์ด๋ ์ดํํธ (feat. startTransition)
Next router.push์ ํตํด ๊ฐ์ ํ์ด์ง ๋ด์์์ ์ด๋ ์, ๋ก๋ฉ fallback์ ์ ์๋ณด์ด๋ ๊ฒ์ผ๊น?
์ด๋ฒ์ ๋ค๋ฃจ๊ณ ์ ํ๋ ์ฃผ์ ๋ ์๊ฐ๋ณด๋ค ์ฌ๋ฌ ์ํฉ์ด ์ฝํ์์๊ณ , ์๊ฐ๋ณด๋ค ๋ ๊น๊ฒ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฏ์ด๋ดค์ด์ผ ํ๋ค.
๋ฌธ์ ์ํฉ
"next": "13.4.13", // page router ์ฌ์ฉ 13.4.6 ์ฌ์ฉ ์ค ๋ฒ๊ทธ๊ฐ ์๋ ๊ฒ์ ํ์ธํ๊ณ ๋ฒ์ ์ฌ๋ ค์ ์งํ
"@tanstack/react-query": "^4.29.13",
"react": "18.2.0"
ํ ์ปดํฌ๋ํธ(AsyncComponent
)๊ฐ ์๊ณ , ์ด ์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ๋ react-query์ useQuery
๋ฅผ suspense
์ต์
์ ํ์ฑํ ํ์ฌ ๊ฐ์ ธ์จ๋ค. ๋ฐ๋ผ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋์, ์๋จ์ ๊ฐ์ธ์ง Suspense
์ fallback์ธ โ๋ก๋ฉ์คโ ํ
์คํธ๊ฐ ๋ณด์ธ๋ค.
์ด์ ์ด ์ปดํฌ๋ํธ์ ๋ฒํผ์ ๋๋ฅด๊ฒ ๋๋ฉด ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ page๋ฅผ 1์ฉ ์ฆ๊ฐ์ํค๊ณ , useQuery์์ ์ฌ์ฉํ๋ ํค์ ์ด page ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๊ฐ ํฌํจ๋์ด ์์ผ๋ฏ๋ก ํค๊ฐ ๋ณ๊ฒฝ๋์ด ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ํจ์นํ๋ค.
function Test() {
return (
<Suspense fallback={<h3>๋ก๋ฉ์ค</h3>}>
<AsyncComponent />
</Suspense>
);
}
function AsyncComponent() {
const router = useRouter();
const page = useQueryParam('page', { parser: Number }) ?? 0;
const { data } = useQuery(
[{ page }, 'key'],
() => fetchFunc(page),
{ suspense: true }
);
return (
<>
<div>{page}</div>
<div>{data}</div>
<Button
onClick={() => {
router.push(
`${router.pathname}${QS.create({ page: page + 1 })}`,
undefined,
{ shallow: true },
);
}}
>
๋ฒํผ
</Button>
</>
);
}
๐ซ ๊ธฐ๋ํ ๋์๊ณผ ์ค์ ๋์
๊ทธ๋ ๋ค๋ฉด, ์์์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๊ฐ ๋ณ๊ฒฝ๋์ด ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ํจ์นญํด์ค๋ ๋์ suspense์ fallback์ธ โ๋ก๋ฉ์คโ์ด ๋ณด์ฌ์ผํ ๊ฒ ๊ฐ์์ง๋ง ์ค์ ๋ก๋ ์ด์ UI๋ฅผ ๊ทธ๋๋ก ์ ์งํ๋ค๊ฐ ๊ฐ์๊ธฐ ํญ, ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ์๋ค.
โ react-query์ keepPreviousData
์ต์
๊ณผ ๊ฐ์ ๋์
๊ต์ฅํ ์ดํดํ ์ ์๋ ๋์์ด์๊ณ , ์ถ์ ํ ์ ์๋ ์์ธ ์ค ํ๋๋ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ React ์ state๋ก์จ ๊ด๋ฆฌ๋๊ณ ์์ง ์๋ค๋ ์ ์ด์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๊ฐ ๋ณ๊ฒฝ๋์์ ๋ React๊ฐ ๋ฆฌ๋ ๋๋ง์ ํด์ผํ๋ค๊ณ ํ๋จํ์ง ๋ชปํ๋ ๊ฒ์ ์๋๊น? ํ๋ ์ฒซ ๋ฒ์งธ ์์ฌ์ ํ๊ฒ ๋์๋ค. (โ ์ฌ์ค ์ด๊ฒ ์์ธ์ ์๋์๋ค.)
์ค์ ๋ก ์๋ ์ฝ๋์ฒ๋ผ page๋ฅผ state๋ก ๊ด๋ฆฌํ๋ฉด ์ฐ๋ฆฌ๊ฐ ์๊ฐํ๋๋๋ก ๋์ํ๋ค. (โ state
๋ก ๊ด๋ฆฌํ๊ณ ๋ง๊ณ ์ ๋ฌธ์ ๊ฐ ์๋๋ผ router.push
๋ฅผ ์ฐ์ง ์์๋ค๋ ์ ์ด ๋ ์ค์ํ๊ฒ ๋ด์ผ ํ๋ ๋ถ๋ถ์ด๋ค.)
์๋ ์ฝ๋
```jsx
function Test() {
return (
<Suspense fallback={<h3>๋ก๋ฉ์ค</h3>}>
<AsyncComponent />
</Suspense>
);
}
function AsyncComponent() {
const router = useRouter();
const [page, setPage] = useState(0);
const { data } = useSuspendedQuery(
[{ page }, 'key'],
() => fetchFunc(page),
{ suspense: true }
);
return (
<>
<div>{page}</div>
<div>{data}</div>
<Button
onClick={() => {
setPage(page + 1);
}}
>
๋ฒํผ
</Button>
</>
);
}
```
๐ ๏ธย ์์ธ๊ณผ ํด๊ฒฐ ๋ฐฉ์
์ฌ์ค ์ด๋ฐ ์ ๋ฐ ์ฝ์ง์ ์ข ํ๋ค.
ํผ์ณ๋ณด๊ธฐ
**state๋ก ๊ด๋ฆฌ๋์ง ์๋ query parameter?**
- ์ด๋ฐ ์ ๋ฐ ์์ฌ๋ค์ ํ๋ฉฐ ๊ณต์ ๋ฌธ์๋ฅผ ๋ค์ ธ๋ณด๋ค๊ฐ, Next.js์ router ๊ด๋ จํด์ [๊ฐ์ ํ์ด์ง ๋ด์์์ ์ด๋](https://nextjs.org/docs/pages/api-reference/functions/use-router#resetting-state-after-navigation)์ด๋ผ๋ ์น์
์์ ํ์ด์ง ์ํ์ ๊ด๋ จ๋ ๋ด์ฉ์ ์ฐพ์๋ค.
> the page's stateย **will not**ย be reset by default as React does not unmount unless the parent component has changed.
>
์ด ๋ฌธ์ฅ์์ `unless the parent component has changed` ์ ํ ๋์ด ํ๋ ค์ query parameter๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ React์ ๋ฆฌ๋ ๋๋ง์ด ์ ๋ฐ๋์ง ์๋๊ฐ๋ณด๋ค, ํ๊ณ ์๊ฐํ๋ค.
- query parameter์ ๋ณ๊ฒฝ โ useQuery์ key ๋ณ๊ฒฝ โ useQuery ๋ฆฌํจ์น โ Suspense์ Promise๊ฐ ์กํ์๋ค๊ฐ fullfilled๋๋ฉด useQuery์ data(์ด๊ฑด state๋ก ๊ด๋ฆฌ๋๋ ๊ฐ์ด๋)๊ฐ ๋ณ๊ฒฝ๋๋ฉฐ ๊ทธ์ ์์ผ ๋ฆฌ๋ ๋๋ง ๋์ด ํ๋ฉด์ ๋ฐ์๋๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ค.
- ๊ทธ๋์ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ธ Suspense์ key๋ฅผ `router.asPath`๋ก ์ฃผ์ด path(query parameter)๊ฐ ๋ณ๊ฒฝ๋ ๋ ๋ง๋ค ๋ช
์์ ์ผ๋ก ์๋ก์ด ์ปดํฌ๋ํธ์์ ์๋ ค์ค์ผ๋ก์จ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค.(๊ณ ์๊ฐํ๋ค.)
์ด ๊ธ์ ์ฐ๋ ์์ ์์ ๋ณด๋ฉด ์๋นํ ๋น์ฝ๋ ๋ง๊ณ ๋
ผ๋ฆฌ์ ์ด์ง๋ ์์ ์๊ฐ์ด์์ผ๋, ๋น์์๋ ์ด ๋ง๋์๋๋ ์ํฉ์ ์ดํดํ ์ ์๋ ์ ๋ฆฌ๋ ํ๋์ ์๊ฐ์ด์๊ธฐ ๋๋ฌธ์ ์ด ์ํ๋ก ์ดํดํ๊ณ ๋์ด๊ฐ๋ค.
***์ฌ์ค,*** query parameter๋ ์ํ๋ก์จ ๊ด๋ฆฌ๋๋๊ฒ ๋ง๋ค. ๊ทธ๋ฌ๊ธฐ ๋๋ฌธ์ ์ปดํฌ๋ํธ ํจ์๊ฐ ๋ค์ ์คํ๋๊ณ ๋ณ๊ฒฝ๋ ์ฟผ๋ฆฌ ํค๋ก ๋ฐ์ดํฐ๋ refetching ํ ์ ์๋ ๊ฒ์ด๋ค.
์์ ์ฝ์ง ํ ๋ฉฐ์น ์ด ์ง๋ startTransition
์ ์ฐ์ฐํ ์ ํ๊ฒ ๋์๊ณ , ์ด๋ฒ ๋ฌธ์ ํด๊ฒฐ์ key๊ฐ ๋์๋ค.
๐งย tl;dr
Suspense๋ฅผ ์ง์ํ๋ ๋ผ์ฐํฐ์ ๊ฒฝ์ฐ, React์์๋ ๋ค๋น๊ฒ์ดํ
์startTransition
์ผ๋ก ๊ฐ์ธ์ ์ ๊ณตํ ๊ฒ์ ๊ถ์ฅํ๋ค.
์ค์ ๋ก Next์ router.push
๋์์ ์์ด์ startTransition
์ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์(page router ๊ธฐ์ค์ผ๋ก ์ด๋ํ๋ ํ์ด์ง์ ํด๋นํ๋ react element๋ฅผ ๊ทธ๋ฆด ๋ ์ฌ์ฉ, app router์ ๊ฒฝ์ฐ ๋ชจ๋ ๋ค๋น๊ฒ์ดํ
๋์์ ์ฌ์ฉ), ๋์ผํ ํ์ด์ง์์ query parameter๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ ์ด๋ฏธ ์กด์ฌํ๋ ์ปดํฌ๋ํธ๋ฅผ ๊ตณ์ด unmount ์ํค์ง(Suspense์ fallback์ ๋ณด์ฌ์ฃผ์ง) ์๋๋ค. ์ด ๋๋ฌธ์ keepPreviousData
์ต์
์ ์ค ๊ฒ ๊ณผ ๊ฐ์ ๋์์ ํ์ธํ ์ ์๋ค.
์ด์ ๋ํ ํด๊ฒฐ์ฑ
์ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ key
๋ฅผ ๋ณ๊ฒฝ์ํค๋ ๊ฒ์ด๋ค. (๊ฒฐ๊ตญ ์ฝ์ง๊ธฐ์์ ์๋ํ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ๊ณผ ๋์ผํ๊ธด ํ๋ค.)
<Suspense fallback={<h3>๋ก๋ฉ์ค</h3>} key={router.asPath()}>
<AsyncComponent />
</Suspense>
startTransition์ด ๋ฌด์์ผ๊น?
startTransition
์ ํตํด ํน์ ์์
์ ์ํํ๋ ๋์, react๋ ์ด๋ฏธ ๊ทธ๋ ค์ง ์ปดํฌ๋ํธ๊ฐ ์๋ค๋ฉด ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์ ์ง์์ผ ํ์ฌ ์ ๊ณตํ๋ UI๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์๋๋ก ํ๋ค. (== Suspense
๋ฅผ ์ฌ์ฉ์ค์ธ ๊ฒฝ์ฐ, ์๋์ ์ผ๋ก fallback์ ๋ณด์ฌ์ฃผ์ง ์๋๋ค.)
์กฐ๊ธ ๋ ๋ฐ์ผ๋ก ๋ด๋ ค๋ณด๋ฉด ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋ scope๋ loading indicators๋ฅผ ํ์ํ์ง ์๊ณ ํธ๋์ง์ ์ด ์ํ๋๋ค๋ ์ค๋ช ์ ์ฐพ์ ์ ์๋ค. ๋ ์์ธํ ์ฌํญ์ ๊ณต์ ๋ฌธ์์ ์์ผ๋ ๊ผญ ์ ๋ ํ์!
useTransition์ ๋ํ ์ค๋ช ์๋ ๋ณด๋ค ์์ธํ๊ฒ ์์ ๊น์ง ๋ค์ด์์ผ๋ฏ๋ก ์ด๊ฒ๋ ํจ๊ป ๋ณด๋ ๊ฒ์ ์ถ์ฒํ๋ค.
- useTransition์์ **Preventing unwanted loading indicators ์น์ ์์ Suspense๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ transition์ ์ฌ์ฉํ๋ฉด ์ด๋ค ๊ฒฐ๊ณผ๊ฐ ๋ํ๋๋์ง ํ์ธํ ์ ์๋ค.
useTransition
๊ณผ ๋ค๋ฅธ ์ ์startTransition
์ ํธ๋์ง์ ์ผ๋ก ์ธํด pending์ด ๋ฐ์ํ๊ณ ์๋์ง ํ์ธํ ์ ์๋isPending
์ ์ ๊ณตํ์ง ์๋๋ค๋ ๊ฒ์ด๋ค.
Next์ router.push๋ ์ด๊ฑธ ์ฌ์ฉํ๋ ๊ฑด ์๋๊น?
์ค์ ๋ก, react ๊ณต์ ๋ฌธ์์์๋ ๋ค๋น๊ฒ์ดํ ์ transition์ผ๋ก ํ๊ธฐํ๋ ๊ฒ์ ์ถ์ฒํ๋ค.
์ค์ ๋ก ํ์ธํด๋ณด๊ธฐ ์ํด, ์ผ๋จ next github์ ๋ค์ด๊ฐ ๋
๋ค startTransition
์ ๊ฒ์ํด๋ณด์๋ค.
๊ฒฐ๊ณผ๊ฐ ๊ฝค ๋์จ๋ค!
์ฌ์ง์ด app router
์ ๊ฒฝ์ฐ ์์ ๋ช
์์ ์ผ๋ก startTransition
์ผ๋ก ๋ค๋น๊ฒ์ดํ
์ ํ๋ค๋ ์ฌ์ค๋ ์ ์ ์์๋ค.
Link๋ฅผ ํตํด ์ด๋ํ๋ ๊ฒฝ์ฐ
router๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ํ๋ ๊ฒฝ์ฐ
๊ทธ์น๋ง ๋๋ page router
๋ฅผ ์ฌ์ฉํ๊ณ ์์์ผ๋ฏ๋ก ์กฐ๊ธ ๋ ๋ด๋ ค๋ณด๋ค๊ฐ react element๋ฅผ ๋ ๋๋ง ํ ๋ startTransition
์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ์์๋๋ค!
์ฝ๋๋ง ์ด๋ฆฌ ์ ๋ฆฌ ํ์ํด๋ณด๊ธฐ์๋ ๋๋ฌด ๊ฑฐ๋ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ ๋ด๊ฐ ์ํ๋ ๋ต์ ๋ฐ๋ก ์ฐพ๊ธฐ ์ด๋ ค์ ๊ณ , ์ค์ ๋ก ์ startTransition
์ ๋บ์ ๋ ๊ธฐ๋ํ๋๋๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํด์ ๊ท๋ฉ์ ์ผ๋ก ๋ต์ ์ฐพ๊ธฐ๋ก ํ๋ค.
์ฐ์ ์๊น ํ ์คํธ๋ก๋ง ์ค๋ช ํ๋ ๋ฌธ์ ์ํฉ์ ์์์ผ๋ก ๋ค์ ํ์ธํด๋ณด์.
๐ gif๋ผ ์กฐ๊ธ ๋๋ ค์..! ํ๊ตญ์ธ์ด์ง๋ง ์กฐ๊ธ๋ง ์ฌ์ ๋กญ๊ฒ ์์ฒญ ๋ฐ๋๋๋ค.
๋ถ๋ชจ ์ปดํฌ๋ํธ(Suspense)์ key๋ฅผ ์ฃผ์์ ๋ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
โ ย ๊ทธ๋ ๋ค๋ฉด patch-package๋ฅผ ์ฌ์ฉํด ์ค์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋๋ฅผ ์์ ํ์ ๋๋?
patch-package๋ฅผ ์ฌ์ฉํด ํจํค์ง๋ฅผ ์ง์ ์์ ํ๋ ๋ฐฉ๋ฒ์ ์ฌ๊ธฐ์ ๋ค๋ฃจ์ง ์๊ฒ ๋ค. ๊ตฌ๊ธ๋งํ๋ฉด ์์ธํ๊ฒ ์ค๋ช ํ๊ณ ์๋ ๋ค๋ฅธ ๊ธ๋ค์ด ๋ง์ผ๋ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋ค.
์๋๋ ์ค์ ๋ก ์์ ํ ์ฝ๋์ด๋ค.
diff --git a/node_modules/next/dist/client/index.js b/node_modules/next/dist/client/index.js
index 2def4d8..86fd856 100644
--- a/node_modules/next/dist/client/index.js
+++ b/node_modules/next/dist/client/index.js
@@ -385,10 +385,12 @@ function renderReactElement(domEl, fn) {
// TODO: Remove shouldHydrate variable when React 18 is stable as it can depend on `reactRoot` existing
shouldHydrate = false;
} else {
- const startTransition = _react.default.startTransition;
- startTransition(()=>{
- reactRoot.render(reactEl);
- });
+ // const startTransition = _react.default.startTransition;
+ // startTransition(()=>{
+ // reactRoot.render(reactEl);
+ // });
+ console.log('start transition ์ ๊ฑฐ');
+ reactRoot.render(reactEl);
}
์ ๋ง๋ก startTransition
์ ์ ๊ฑฐํ๋๊น ์ฒ์ ๊ธฐ๋ํ๋ ๊ฒ๊ณผ ๊ฐ์ด ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค!
๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ํด๊ฒฐํด์ผ ํ ๊น?
์ฌ์ค react ๊ณต์ ๋ฌธ์์ Suspense ์ชฝ์๋ startTransition์ด ๋ฑ์ฅํ๋ค. React๋ ์ด๋ฏธ ๋ณด์ฌ์ง๊ณ ์๋ ํ๋ฉด์ ๋ฉ์ถ๊ณ ๋ก๋ฉ fallback์ ๋ณด์ฌ์ฃผ๋ ๊ฒ์ ์ฌ์ฉ์ ๊ฒฝํ์ ํด์น ์ ์๋ค๊ณ ๋งํ๋ฉฐ, ์ด๋ฅผ ํด์ํ ์ ์๋ ๋ฐฉ์์ผ๋ก startTransition
์ ์๊ฐํ๊ณ ์๋ค.
๋ํ Suspense-enabled router(Suspense๋ฅผ ์ง์ํ๋ ๋ผ์ฐํฐ)๋ ๋ด๋ถ์ ์ผ๋ก startTransition
์ ๋ํํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํด๋ฒ๋ฆฐ๋ค. (์๊ธฐ๋ค์ด ์ถ์ฒํ๋ ๋ฐฉ์์ด๋ฏ๋ก ๋ฐ๋ฅด๋ผ๋ ๊ฒ์ด์ง!)
๊ทธ๋ฆฌ๊ณ ์ ํํ๊ฒ ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ฐฉ์์ ํจ๊ป ์๊ฐํ๊ณ ์์ผ๋ฉฐ, ๊ฒฐ๋ก ์ ์ผ๋ก๋ query parameter ๋ฑ์ด ๋ณ๊ฒฝ๋์์ ๋ React์๊ฒ ์ด๊ฑด ์๋ก์ด ์ปดํฌ๋ํธ์์ ์๋ ค์ฃผ์ด์ผ ํ๋ค๊ณ ํ๋ค.
**Resetting Suspense boundaries on navigation**
- ์ด๋ key props๋ฅผ ํตํด ๋ฌ์ฑํ ์ ์๊ณ , ๋์ ๊ฒฝ์ฐ์๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ธ Suspense์ key๋ฅผ ์ฃผ์ด ํด๊ฒฐํ๋ค.
<Suspense fallback={<Txt>๋ก๋ฉ์ค</Txt>} key={router.asPath()}>
<AsyncComponent />
</Suspense>
โ ๏ธ ์์ํ ์ํ ์ฐฉ์ค
์ฐ์ฐํ ํ
์คํธ๋ฅผ ํ๊ณ ์๋ Next ๋ฒ์ ์ด 13.4.6
์ด์๋๋ฐ, ์ฌ๊ธฐ์ ๊ฐ์ ๊ฒฝ๋ก๋ก ์ด๋ํ์ ๋ ์์ ํ์ด์ง๋ฅผ ๋ค์ ๊ทธ๋ฆฌ์ง๋ ์๋ ๊ต์ฅํ ์ด์ํ ๋์์ ํ๋ค.
13.3.x
๋ฒ์ ๋๋ก ๋ฎ์ถ๊ฑฐ๋13.4.13~
์ธ ์ต์ ๋ฒ์ ์ผ๋ก ๋ค์ ์ค์นํ์ ๋๋ ์ ์์ ์ผ๋ก ๋์ํ๋ค.13.4.6
๋ฒ์ ์์ HTTPยdelete
ย ๋ฉ์๋ ๊ด๋ จํด์ย body์ data๋ฅผ ๋๊ฒจ์ค๋ ํญ์ ๋น์ด์๋ย ์ด์๋ ์๋ค๊ฐ ์ดํ ๋ฒ์ ์์ ์์ ๋์๋๋ฐ ์๋ฌด๋๋ ๋ง์ ๋ฒ์ ์ธ ๊ฒ ๊ฐ๋คโฆ. ใ ใทใ ใท- ๋ค์ ํ ๋ฒ.. ์๋ฌด๋ฆฌ ๋์ค์ ์ผ๋ก ๋ง์ด ์ฌ์ฉ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๊ณ ํด๋ ์์ฒด์ ์ธ ๋ฒ๊ทธ๊ฐ ์์ ์ ์๋ค๋ ์ฌ์ค์ ์๊ฐํ๋ค.
์คํ์ ๋ก์คํฌ. goo
# ์นดํ ๊ณ ๋ฆฌ
- BOJ 36
- Algorithm 12
- CodingTest 11
- Web 9
- Javascript 8
- Vue 7
- React 7
- DBProject 4
- Python 3
- Tech-interview 3
- Express 3
- Next 3
- Github 2
- Django 2
- C 1
- C++ 1
- WebGame 1