์ ๊ทผ (์์ฝ)
Next.js ๋ฅผ ํตํด ๊ฐ๋ฐ์ ์งํํ๋๋ฐ, Web App์ ์๋ฒ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์์ ์ด๋ค.
๊ณต์ ์น์ฌ์ดํธ๋ฅผ ํ์ธ ํด๋ณด๋ฉด, npm ์์์ ๋์ ๋ค์ด๋ก๋ ์๊ฐ 18์ต์ ์ก๋ฐํ๊ณ ์ค์๊ฐ์ผ๋ก ์์น๊ฐ ์์นํ๋ ๊ฒ์ ๋ณด๊ธฐ๋ง ํด๋
์ผ๋ง๋ ํซํ ๊ธฐ์ ์ธ์ง ํ์ธ์ด ๊ฐ๋ฅํ๋ค. ์ด๋ฅผ ํ๋ก์ ํธ์ ๋์ ํ์ฌ ์น์ดํ๊ฒ ์ฐ๊ตฌ๋ฅผ ํด๋ณด๊ณ ์ ํ๋ค.
(์์ ์ ๊ฐ๋ฐ ๋์ ๋๋ฌธ๋๋ฌธ ํ์ฉํ๋ ๊ฒ ๊ทธ ์ด์์ผ๋ก ์น์ํด์ง๊ณ ์ ํ๋ค)
1. ReactQuery ์ค์น
- npm install @tanstack/react-query
- npm install @tanstack/react-query-devtools
2. ESLint Plugin ์ค์น
- npm i -D @tanstack/eslint-plugin-query
- ๊ธฐํ ์ค์ (.eslintrc.json)
3. ReactQuery ์ค์
- (1) queryClient.ts (→index.ts) ์์ฑ ํ ๋ด๋ณด๋ด๊ธฐ (feat. layout.tsx)
- (2) (node_modules ์) QueryClientProvider.tsx ๋ค๋ฃจ๊ธฐ (→QueryClientProviderWrapper.tsx) (๊ฐ์ข import)
- (3) layout.tsx์ ReactQuery ์ฌ์ฉํ๊ณ ๊ตฌ๋ ํ ์ ์ํ์ธ
๋ฐฉ๋ฒ
1. React Query ์ค์น
npm install @tanstack/react-query
npm install @tanstack/react-query-devtools
* devtools๋ฅผ dependency์ฑ์ด ์๋, ์ผ๋ฐ์ผ๋ก ์ค์นํ๋ ์ด์ ?
- ์ฑ ์ปดํฌ๋ํธ๋ค์์ devtools๋ฅผ ๊ฐ์ ธ์ ์ถ๊ฐํ๋ค์, devtools๋ฅผ ์ฌ์ฉํด node ํ๊ฒฝ์ ํ ์คํธํ๊ฒ ๋๋๋ฐ,
- node ํ๊ฒฝ์ด development์ธ ๊ฒฝ์ฐ ์ด๋ฅผ ํฌํจํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
# ์ฐธ๊ณ
https://tanstack.com/query/latest/docs/framework/react/devtools#devtools-in-production
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
By default, React Query Devtools are only included in bundles when process.env.NODE_ENV === 'development', so you don't need to worry about excluding them during a production build.
>> Lazy load ๋ฅผ ํ ๊ฒฝ์ฐ, Bundles์์ ์ ์ธ๋๋๋ก ์ค์ ํ ์ ์๋ค.
>> ๋ํ ๋ธ๋ผ์ฐ์ ์ฝ์์์ window.toggleDevtools๋ฅผ ํธ์ถํ ์๋ ์๋ค.
- ์ด๋ฅผ ํตํด, ํ๋ก๋์
ํ๊ฒฝ์์๋ dev tools๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
2. ESLint Plugin ์ค์น
npm i -D @tanstack/eslint-plugin-query
- ์ค์น ์ดํ, eslint.cjs (eslint config)์ extends array์ ํ ์ค ์ถ๊ฐํ ๊ฒ์ด ์์
[eslintrc]
To enable all of the recommended rules for our plugin, add plugin:@tanstack/query/recommended in extends:
[๊ณต์๋ฌธ์์์๋]
{
"extends": ["plugin:@tanstack/query/recommended"]
}
→ [๊ฐ์์์ ] "plugin:@tanstack/eslint-plugin-query/recommended",
(1). exhaustive dependencies ๊ท์น
{
"plugins": ["@tanstack/query"],
"rules": {
"@tanstack/query/exhaustive-deps": "error"
}
}
- ์์ ๊ฐ์ด ์ค์ ํด์ฃผ๋ฉด, QueryKey(์ฟผ๋ฆฌํค)์ QueryFn(์ฟผ๋ฆฌํจ์)์ ๋ชจ๋ dependencies๊ฐ ํฌํจ๋์ด
- dependencies๊ฐ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ, Query๊ฐ ๋ค์ ์คํ๋๋๋ก ํ ์ ์๋ค.
3. ReactQuery ์ค์
(1). queryClient.ts (→ index.ts) ์์ฑ ํ ๋ด๋ณด๋ด๊ธฐ (feat. layout.tsx)
1. root/react-query ํด๋๐๏ธ ์์ฑ
2. root/react-query/index.ts ํ์ผ๐ ์์ฑ
[./react-query/index.ts]
import {QueryClient} from "@tanstack/react-query";
export const queryClient = new QueryClient();
- queryClient๋ฅผ ๋ง๋ค์ด ๋ด๋ณด๋ด, ์ฌ์ฉํ ์ ์๊ฒ ๋ง๋๋ ๊ฒ๋ถํฐ ์์
(2). (node_modules ์) QueryClientProvider.tsx ๋ค๋ฃจ๊ธฐ (→ QueryClientProviderWrapper.tsx) (๊ฐ์ข import)
(ใฑ-1). QueryClientProviderWrapper.tsx ์์ฑ
'use client';
import {queryClient} from "@/react-query/index";
import {QueryClientProvider} from "@tanstack/react-query";
import {ReactQueryDevtools} from "@tanstack/react-query-devtools";
export default function QueryClientProviderWrapper({children}: { children: React.ReactNode }) {
return (
<>
<QueryClientProvider client={queryClient}>
{children}
<ReactQueryDevtools/>
</QueryClientProvider>
</>
);
}
- QueryClientProvider → queryClient → ReactQueryDevTools
<ReactQueryDevTools /> ๋ QueryClientProvider ๋ด๋ถ์๋ง ์กด์ฌํ๋ค๋ฉด ์ด๋๋ OK
(ใด-1). (node_modules ์ ๊ณต๋๋) (if) QueryClientProvider.tsx ์ฌ์ฉ
'use client'
import * as React from 'react'
import type { QueryClient } from '@tanstack/query-core'
export const QueryClientContext = React.createContext<QueryClient | undefined>(
undefined,
)
export const useQueryClient = (queryClient?: QueryClient) => {
const client = React.useContext(QueryClientContext)
if (queryClient) {
return queryClient
}
if (!client) {
throw new Error('No QueryClient set, use QueryClientProvider to set one')
}
return client
}
export type QueryClientProviderProps = {
client: QueryClient
children?: React.ReactNode
}
export const QueryClientProvider = ({
client,
children,
}: QueryClientProviderProps): React.JSX.Element => {
React.useEffect(() => {
client.mount()
return () => {
client.unmount()
}
}, [client])
return (
<QueryClientContext.Provider value={client}>
{children}
</QueryClientContext.Provider>
)
}
2. ์ ๊ณต๋ ๊ฒ์ ๊ฐ์ ธ๋ค๊ฐ ์ฌ์ฉํ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
import {QueryClientProvider} from "@tanstack/react-query";
import {ReactQueryDevtools} from "@tanstack/react-query-devtools";
import {queryClient} from "@/react-query/queryClient";
export function App() {
return (
<QueryClientProvider client={queryClient}>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/Staff" element={<AllStaff/>}/>
<Route path="/Calendar" element={<Calendar/>}/>
<Route path="/Treatments" element={<Treatments/>}/>
<Route path="/signin" element={<Signin/>}/>
<Route path="/user/:id" element={<UserProfile/>}/>
</Routes>
<ReactQueryDevtools/>
</QueryClientProvider>
);
}
(3). layout.tsx์ ReactQuery ์ฌ์ฉํ ์ค๋นํ๊ธฐ (๊ฐ์ข import)
1. root/app/layout.tsx ๐ ์ ๊ทผ
[./app/layout.tsx]
import type {Metadata} from "next";
import {Geist, Geist_Mono} from "next/font/google";
import "./globals.css";
import QueryClientProviderWrapper from "@/react-query/QueryClientProviderWrapper";
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<QueryClientProviderWrapper>
{children}
</QueryClientProviderWrapper>
</body>
</html>
);
}
- ๋ง๋ค์ด๋์ <QueryClientProviderWapper>๋ก ๊ฐ์ผ๋ค
'๐ป DEV > React-Query' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ReactQuery] (4) ReactQuery - useIsFetching (feat. Nextjs) (0) | 2025.03.19 |
---|---|
[ReactQuery] (1) ReactQuery ๋ ๋ฌด์์ธ๊ฐ? (0) | 2025.03.15 |
[ReactQuery] (3) ReactQuery - customHooks (feat. Nextjs) (0) | 2025.03.15 |
๋๊ธ