-
๋ก๋ฉ๊ณผ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ ์ด์ ๋ ๋ญ๊น?
- ๋ฐ์ดํฐ ํ์นญ์ ๋ฌธ์ ๊ฐ ์๊ธธ ๊ฒฝ์ฐ, ์๋ฌ ๋ฐ์ ์์ด ๋ฐ์ดํฐ ํ์นญ์ด ์๋ชป๋์๋ค๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฉ์ถ์ง ์๊ณ ์๋ ค์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
- ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ค์ธ ๋ก๋ฉ ์ํ๋ฅผ ์ฒ๋ฆฌํ์ฌ ๋ก๋ฉ ํ์ด์ง๋ฅผ ๋์ฐ๋ ๋ฑ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๋ฐ์ ํ์ฉํ ์ ์๋ค.
-
React Query๋ฅผ ํ์ฉํ์ฌ ๋ก๋ฉ, ์๋ฌ์ฒ๋ฆฌ ํ๊ธฐ
- ๋ฆฌ์กํธ ์ฟผ๋ฆฌ๊ฐ ์ ๊ณตํ๋ ์์ฑ ์ค ๋ก๋ฉ๊ณผ ์๋ฌ ์ํ๋ฅผ ์ฒ๋ฆฌํด์ฃผ๋
isLoading
,isError
๋ฅผ ํ์ฉํ ์ ์๋ค.const {data, isLoading, isError} = useQuery(...); if(isLoading) return <div>๋ก๋ฉ ํ๋ฉด</div> if(isError) return <div>์ค๋ฅ ํ๋ฉด</div>
- ๋ฆฌ์กํธ ์ฟผ๋ฆฌ๊ฐ ์ ๊ณตํ๋ ์์ฑ ์ค ๋ก๋ฉ๊ณผ ์๋ฌ ์ํ๋ฅผ ์ฒ๋ฆฌํด์ฃผ๋
-
React์์์ ์๋ฌ ํธ๋ค๋ง
- ๋ณดํต api ํธ์ถ์
try ~ catch
๋ฌธ์ ํตํด ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ๋ค. ๊ทธ๋ฌ๋ ์ด๋ฌํ ๋ฐฉ์์ ํ๋์ ์ปดํฌ๋ํธ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๊ฒฝ์ฐ์ ์๋ ๊ฒฝ์ฐ์ ์ฝ๋๋ฅผ ๊ฐ๊ฐ ์์ฑํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ค. - ErrorBoundary
- React 16 ๋ฒ์ ๋ถํฐ ๊ฐ๋ ๋์
- ErrorBoundary ์ปดํฌ๋ํธ ํํ
class ErrorBoundary extends React.Component { constructor(props) { super(props); // ์ปดํฌ๋ํธ์ ์ด๊ธฐ ์ํ ์ค์ this.state = { hasError: false }; } // ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ํธ์ถ๋๋ ๋ฉ์๋ static getDerivedStateFromError(error) { // ์ํ๋ฅผ ์ ๋ฐ์ดํธํ์ฌ ์๋ฌ ๋ฐ์ ์ฌ๋ถ๋ฅผ ํ์ return { hasError: true }; } // componentDidCatch()๋ ์๋ฌ๊ฐ ๋ฐ์ํ ํ ํธ์ถ๋๋ ๋ฉ์๋ componentDidCatch(error, errorInfo) { // ์๋ฌ ์ ๋ณด์ ํจ๊ป ์๋น์ค์ ์๋ฌ ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํ๋ ํจ์ ํธ์ถ logErrorToMyService(error, errorInfo); } render() { // ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ ์๋ฌ ๋ฉ์์ง๋ฅผ ํ์ if (this.state.hasError) { return <h1>Something went wrong.</h1>; } // ์๋๋ฉด ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง return this.props.children; } } ์ถ์ฒ: https://lasbe.tistory.com/183 [LasBe's Upgrade:ํฐ์คํ ๋ฆฌ]
getDerivedStateFromError(error)
- ํ์ ์ปดํฌ๋ํธ์์ ๋ฐ์ํ ์๋ฌ๋ฅผ ์์ ์ปดํฌ๋ํธ๊ฐ ๊ฐ์ง
- ์๋ฌ ๋ฐ์ ์ฌ๋ถ๋ฅผ ์ปดํฌ๋ํธ ์ํ์ ๋ฐ์ํ์ฌ ์
๋ฐ์ดํธ (
hasError
)
- ์์์์ ์๋ฌ ํธ๋ค๋ง์ ์ ์ธํ์ฌ ํ์์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ฉด, ํ์ ์ปดํฌ๋ํธ์์๋ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ๋ณ๋๋ก ๋ค๋ฃจ์ง ์์๋ ๋๋ค.
- ๋ณดํต api ํธ์ถ์
๊ธฐ์กด์ Client State ๊ด๋ฆฌ๋
- Redux
- React Context API
- Recoil
๋ฑ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด ๊ด๋ฆฌํ๋ค.
Client์์ API์ ํต์ ์ ํ๊ธฐ ์ํด์๋ ์ถ๊ฐ์ ์ผ๋ก useEffect, useState๋ฅผ ํจ๊ป ์ฐ๋ฉด์ ๋ฐ์ดํฐ๋ฅผ fetching ํด์๋ค.
ํ์ง๋ง ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ ํ ๋ค์ ํ์์ฑ์ด ์ฌ๋ผ์ง๋ค.
React์์ ๋ฐ์ดํฐ fetching
๊ณผ ์บ์ฑ ํ๋ก์ธ์ค
๋ฅผ ๊ฐ์ํํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ์ธ๋ถ(API ๋ฑ)๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ fetching ๋ฐ ์ ๋ฐ์ดํธ ๊ณผ์ ๊ฐ์ํ
- API ์์ฒญ์ ๋ก๋ฉ ๋ฐ ์ค๋ฅ ์ํ ๊ด๋ฆฌ
- ์บ์ฑ ์๋ ๊ด๋ฆฌ
Query
- API ์๋ํฌ์ธํธ, DB ๋ฑ์ ์๊ฒฉ ๋ฐ์ดํฐ ์์ค๋ก๋ถํฐ ๋ฐ์ดํฐ ์์ฒญ
- useQuery ํ ์ฌ์ฉ
Mutation
- ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ๋ฐ์ดํธ
- useMutation ํ ์ฌ์ฉ
Query Caching
- Query ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ
Query Invalidation
- ์ฟผ๋ฆฌ๋ฅผ ์ค๋๋ ์ํ๋ก ์ฌ๊ฒจ ๋ฌดํจํ
๋ฐ์ดํฐ Fetching ์ฉ
API ์๋ํฌ์ธํธ๋ DB์์ ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ธ์ค๋๋ก ์๋ฒ์ ์์ฒญํ๋ ๊ฒ
const query = useQuery( { queryKey: [ โkeyโ ], queryFn: callback })
queryKey
- ์ฟผ๋ฆฌ์ ๊ณ ์ ํค
- React Query ์ต์ ๋ฒ์ ๋ถํฐ๋ ๋ฐฐ์ด ํ๊ธฐ๋ฒ์ ์ฌ์ฉํด์ ํค ์ง์
queryFn
- ํ ํธ์ถ ์ ์คํ๋๋ Promise ๋ฐํํ๋ ํจ์
- ํด๋น callbackํจ์์์ ๋ฐ์ดํฐ fetching
// ์์
const getProducts = () => fetch( '<https://jsonplaceholder.typicode.com/users>')
.then( res => res.json() )
const query = useQuery( { queryKey: [โusersโ], queryFn: getTodos })
๋ฐํ๊ฐ
์ฟผ๋ฆฌ์ ์ํ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด
const { isLoading, isError, data, error, refetch, remove } = useQuery( { queryKey: [โtodosโ], queryFn: getTodos });
๋ํ์ ์ธ ํ๋กํผํฐ
isLoading
์ฟผ๋ฆฌ๊ฐ ํ์ฌ ๋ก๋ฉ ์ค์ธ์ง ์ฌ๋ถ (boolean)isError
์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ ์ค๋ฅ์ธ์ง ์ฌ๋ถ (boolean)data
์ฟผ๋ฆฌ๋ฅผ ํตํด ์ฑ๊ณต์ ์ผ๋ก fetching๋ ๋ฐ์ดํฐerror
์ฟผ๋ฆฌ ์คํ ์ค ๋ฐ์ํ ๋ชจ๋ ์๋ฌrefetch
์ฟผ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์๋์ผ๋ก refetch ํ๋ ํธ๋ฆฌ๊ฑฐ ๋ฉ์๋remove
์บ์์์ ํน์ ์ฟผ๋ฆฌ ์ ๊ฑฐํ๋ ๋ฉ์๋
useQuery
๋ ๊ธฐ๋ณธ์ ์ผ๋ก
- ์ปดํฌ๋ํธ ์ต์ด mount ์์ ๋ฐ์ดํฐ๋ฅผ fetchingํด์ค๊ณ ,
- ์ดํ์ ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ์ ๋ํด์๋ ์๋ ์คํ๋์ง ์๋๋ค. (๋ฐ์ดํฐ refetching ์ํด์ค)
[ useQuery ์ต์ ]
์ต์ | ์ญํ | ๊ธฐ๋ณธ๊ฐ |
---|---|---|
refetchOnWindowFocus | ๋ฐ์ดํฐ๊ฐ ์ค๋๋(stale) ๊ฒฝ์ฐ ๋ธ๋ผ์ฐ์ ์ฐฝ์ด ํฌ์ปค์ค ๋๋ฉด ๋ฆฌํ์น | true |
refetchOnMount | ๋ฐ์ดํฐ๊ฐ ์ค๋๋ ๊ฒฝ์ฐ ๋ง์ดํธ ์ ๋ฆฌํ์น | true |
refetchOnReconnect | ๋ฐ์ดํฐ๊ฐ ์ค๋๋ ๊ฒฝ์ฐ ์ฌ์ฐ๊ฒฐ ์ ๋ฆฌํ์น | true |
ํ์ง๋ง ๋ธ๋ผ์ฐ์ ๊ฐ idle ์ํ๋ฅผ ์ ์งํ ๋์, ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ๋ฅผ ๊ฐ์งํ์ฌ ์๋์ผ๋ก ๋ฆฌํ์นํด์ฃผ์ง ์๋๋ค.
์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด์ refetchIntervel
์ต์
์ ์ฌ์ฉํ ์ ์๋ค.
- ์ค์ ํ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ๋ฐ์ดํฐ๋ฅผ ๊ณ์ refetching ํด์ด
API ์๋ํฌ์ธํธ๋ DB์ ๋ฐ์ดํฐ๋ฅผ ์๋ก ์์ฑ, ์์ , ์ญ์
const mutation = useMutation({ mutationFn: mutationFunction });
mutationFn
- ํ์ ์ต์ .
- ์คํํ๊ณ ์ ํ๋ ํจ์๋ฅผ ๋ฐํํ๋ ํจ์
- ์์
const AddUser = useMutation({ mutationFn: ( user ) => { return fetch('<https://jsonplaceholder.typicode.com/users>', { method:'post', headers: { "Content-Type": "application/json", }, body:JSON.stringify( user ) }).then( res => res.json() ) })
๋ฐํ๊ฐ
๋ฎคํ
์ด์
์คํ ๊ฒฐ๊ณผ์ ๊ด๋ จ๋ ์ ๋ณด๋ฅผ ๋ด์ ๊ฐ์ฒด
๋ํ์ ์ธ ํ๋กํผํฐ
isLoading
๋ฎคํ ์ด์ ์ด ํ์ฌ ๋ก๋ฉ ์ค์ธ์ง ์ฌ๋ถ (boolean)isSuccess
๋ฎคํ ์ด์ ๊ฒฐ๊ณผ๊ฐ ์ฑ๊ณต์ธ์ง ์ฌ๋ถ (boolean)isError
๋ฎคํ ์ด์ ๊ฒฐ๊ณผ๊ฐ ์ค๋ฅ์ธ์ง ์ฌ๋ถ (boolean)data
๋ฎคํ ์ด์ ์คํ ํ ๋ฐํ๋ ๋ฐ์ดํฐ (์์ ๋๋ง)mutate
ํด๋น ๋ฎคํ ์ด์ ์คํ์ ์ํด ํธ์ถํ ๋ฉ์๋. (์ธ์์ ๋ด์ ๋ณ์๋ฅผ ๊ฐ์ฒด๋ก ์ ๋ฌ)reset
๋ฎคํ ์ด์ ์ด๊ธฐ ์ํ๋ก ๋ฆฌ์ ํ๋ ๋ฉ์๋onSuccess
๋ฎคํ ์ด์ ์ฑ๊ณต์ ํธ์ถํ ์ฝ๋ฐฑํจ์onError
๋ฎคํ ์ด์ ์คํจ์ ํธ์ถํ ์ฝ๋ฐฑํจ์
์๊ฒฉ ์๋ฒ์ ํต์ ํ๋๋ฐ์ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ๋จ์ถํ๊ณ ์,
์ฌ๋ฌ๋ฒ ๋ถ๋ฌ์ฌ ๋ฐ์ดํฐ๋ ์บ์์ ์ ์ฅํ์ฌ ๋ฐ๋ณตํด์ ํ์๋ก ํ ๊ฒฝ์ฐ ์๊ฒฉ ์๋ฒ๊ฐ ์๋ ์บ์์์ ๋น ๋ฅด๊ฒ ๊ฐ์ ธ์ฌ ์ ์๋ ๋ฐฉ์
useQuery ํ
์ฌ์ฉ ์, ์ง์ ํ๋ ๊ณ ์ ํค
๋ฐ์ ๋ฐํ๋ ๋ฐ์ดํฐ๊ฐ ์บ์ฑ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก๋ ์บ์ ๋ฐ์ดํฐ๋ ์ค๋๋(stale) ์ํ๋ก ๊ธฐ๋ก๋๋ค.
[ Query Caching๊ณผ ๊ด๋ จ๋ useQuery ์ต์ ]
const query = useQuery({
queryKey: [โusersโ],
queryFn: getUsers,
staleTime: 5000,
cacheTime: 60000
})
staleTime
- xx๋ฐ๋ฆฌ์ด ํ์ ๋ฐ์ดํฐ๋ stale ์ํ๋ก ์ฒ๋ฆฌ๋๋ค.
cacheTime
- xx๋ฐ๋ฆฌ์ด ํ์ ์บ์ ๋ฐ์ดํฐ๋ ๊ฐ๋น์ง ์ปฌ๋ ์ ์ผ๋ก ๊ฐ๋ค. (๋ฒ๋ ค์ง)
์ง์ ํด์ค staleTime
๊ณผ ๋ฌด๊ดํ๊ฒ ์ฆ์ ๋ฐ์ดํฐ๋ฅผ stale ์ํ๋ก ์ฒ๋ฆฌํด์ผํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
์๋ฅผ ๋ค์ด, API์ POST ์์ฒญ์ ๋ณด๋ด ๋ฐ์ดํฐ ๊ฐ์ ์ ๋ฐ์ดํธํ ๋์, API ์๋ํฌ์ธํธ์ ์๋ ๋ฐ์ดํฐ์ ๊ฐ์ด ์บ์์ ์ ์ฅ๋์ด์๋ ๊ฐ๋ณด๋ค ๋ ์ต์ ์ํ๊ฐ ๋๊ณ , ์บ์์ ์ ์ฅ๋์ด์๋ ๋ฐ์ดํฐ๋ ๊ณง๋ฐ๋ก outdatedํ ๊ฐ์ด ๋์ด๋ฒ๋ฆฐ๋ค. ์ด๋ด ๋์ ์ฆ์ ์บ์ ๋ฐ์ดํฐ๋ฅผ stale ์ํ๋ก ์ฒ๋ฆฌํด์ค์ผ ํ๋ค.
React Query์ QueryClient ๊ฐ์ฒด์ invalidateQueries ๋ฉ์๋ ํ์ฉ
- ๋ชจ๋ ์ฟผ๋ฆฌ, ํน์ ๊ณ ์ ํค๋ฅผ ํตํด ํน์ ์ฟผ๋ฆฌ๋ฅผ stale ์ํ๋ก ์ฒ๋ฆฌํด์ฃผ๋ ์ญํ
useQueryClient
ํ ์ ํตํด queryClient ๊ฐ์ฒด ์์ฑ- ๊ฐ์ฒด ๋ด์ฅ ๋ฉ์๋
invalidateQueries
ํ์ฉํ๊ธฐ
import { useQueryClient } from "@tanstack/react-query";
// useQueryClient ํ
์ ์ฌ์ฉํ์ฌ queryClient ๊ฐ์ฒด ์์ฑ
const queryClient = useQueryClient();
// ์บ์์ ๋ชจ๋ ์ฟผ๋ฆฌ ๋ฌดํจํ
queryClient.invalidateQueries();
// 'users'๋ก ์์ํ๋ ํค๊ฐ ์๋ ๋ชจ๋ ์ฟผ๋ฆฌ ๋ฌดํจํ
queryClient.invalidateQueries({ queryKey: ["users"] });
- React ํ ์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ๊ฐํธํ๊ฒ Fetch/Update ํ ์ ์๋ค!
- ์ค๋งํธ ์บ์ฑ ๋ฉ์ปค๋์ฆ์ ํตํด ์ฑ๋ฅ์ ์ต์ ํํ ์ ์๋ค!!
์ ๋ฆฌํ์๋ฉด, ์ฝ๋ ๊ฐ์ํ & ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด Fetching Library๋ฅผ ์ฌ์ฉํ ์ ์๋ค