React Query๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

React Query๋Š” ์„œ๋ฒ„์˜ ๊ฐ’ Fetching, Cashing, ๋™๊ธฐํ™”, ์„œ๋ฒ„ ๊ฐ’ ์—…๋ฐ์ดํŠธ, ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋“ฑ ๋น„๋™๊ธฐ ๊ณผ์ •์„ ์ง๊ด€์ ์ด๊ณ  ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ React๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋งˆ์ฃผํ•˜๊ฒŒ ๋˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฌธ์ œ์  ์ค‘ ์ œ์ผ ๋Œ€ํ‘œ์ ์ธ ํ•˜๋‚˜๊ฐ€ state ์ƒํƒœ ๊ด€๋ฆฌ์— ๊ด€ํ•œ ๋ถ€๋ถ„์ธ๋ฐ์š”. ๋Œ€ํ‘œ์ ์œผ๋กœ React์˜ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋„๊ตฌ์—๋Š” redux๋‚˜ recoil ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์กด์žฌํ•˜์ง€๋งŒ, ์ด๋Ÿฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ ํด๋ผ์ด์–ธํŠธ ์ชฝ์˜ ๋ฐ์ดํ„ฐ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ธฐ์—” ์ ํ•ฉํ•  ์ˆœ ์žˆ์–ด๋„ ์„œ๋ฒ„ ์ชฝ์˜ ๋ฐ์ดํ„ฐ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ธฐ์—” ์ ํ•ฉํ•˜์ง€ ์•Š์€ ์ ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ์ชฝ ์œ„์ฃผ๋กœ ์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋„๊ตฌ๋“ค์„ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด ์–ด๋А ์ˆœ๊ฐ„๋ถ€ํ„ฐ ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ์™€ ์„œ๋ฒ„ ์ƒํƒœ๊ฐ€ ํ•จ๊ป˜ ๊ณต์กดํ•˜๊ฒŒ ๋˜๊ณ  ๊ทธ ๋ฐ์ดํ„ฐ๋“ค์ด ์„œ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜๋ฉด์„œ ์• ๋งคํ•œ ์ƒํƒœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋˜์–ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ์„œ๋ฒ„์—๋Š” ์ด๋ฏธ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜ ๋ฒ„๋ฆฐ ๋ฐ์ดํ„ฐ๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ์ „ ๋ฐ์ดํ„ฐ๋กœ ์œ ์ €์—๊ฒŒ ๋ณด์ด๊ฑฐ๋‚˜ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. React query๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ›จ์”ฌ ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

React Query๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์€ ์˜ˆ๋กœ๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์ „์—ญ ์ƒํƒœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ admin ํŽ˜์ด์ง€์™€ ๊ฐ™์€ ๊ด€๋ฆฌํ˜• ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋™์‹œ์— ๋‘ ๋ช…์˜ ๊ด€๋ฆฌ์ž๊ฐ€ ๊ฐ™์€ ํ™”๋ฉด์„ ๋ณด๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ํ•œ ๊ด€๋ฆฌ์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๊ด€๋ฆฌ์ž๋„ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋Š” ํด๋ผ์ด์–ธํŠธ ์ชฝ๋ณด๋‹ค๋Š” ์„œ๋ฒ„ ์ชฝ์—์„œ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ๋” ์ ํ•ฉํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๊ณ  React Query๋ฅผ ์ ์šฉํ•œ๋‹ค๋ฉด ์ด ๊ตฌ์กฐ๋ฅผ ๋” ๋‹จ์ˆœํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


React Query์˜ ์žฅ์ 

โœ… Data Fetching ๋˜๋Š” ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ๋‹จ์ˆœํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const getServerData = async () => {
  const data = await fetch("...").then((response) => response.json());
  return data;
};

// Before
export default function App() {
  const [data, setData] = useState([]);

  useEffect(() => {
    getServerData()
      .then((result) => setData(result))
      .catch((e) => ... );
  }, []);

  return <div>{JSON.stringify(data)}</div>;
}

// After
export default function App() {
  const { data } = useQuery(["dataKey"], getServerData);
  return <div>{JSON.stringify(data)}</div>;
}

useState๊ณผ useEffect๋ฅผ ์‚ฌ์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๊ณผ์ •์„ React query๋ฅผ ํ†ตํ•ด์„œ ๋‹จ์ˆœํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. React query๋ฅผ ์‚ฌ์šฉํ•จ๊ณผ ๋™์‹œ์— ์ฝ”๋“œ ์ˆ˜๋ฅผ ์ค„์ผ์ˆ˜ ์žˆ๊ณ  useEffect๋กœ ์ธํ•ด์„œ ๋ฐœ์ƒํ•˜๋Š” Side Effect๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ React query๊ฐ€ ๋‚ด์žฅ๋œ ๊ธฐ๋Šฅ์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ด€๋ จ ๋กœ์ง๋“ค์„ ์ „๋ถ€ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ์— ํŒ€ ํ”„๋กœ์ ํŠธ์•ˆ์˜ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋™์ผํ™” ๋œ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ์„œ๋กœ์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ์ „์ฒด์ ์ธ ํ๋ฆ„์„ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ์‰ฌ์›Œ์ง€๊ฒŒ ๋˜๊ณ  ์ˆ˜์ •ํ•˜๋Š” ์ผ์ด ์ข€ ๋” ์ˆ˜์›”ํ•ด ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


โœ… ๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ์œ„ํ•ด API๋ฅผ ํ˜ธ์ถœํ• ๋•Œ react query๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋™๊ธฐ์ ์œผ๋กœ ์—ฌ๋Ÿฌ API๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋‚˜์•„๊ฐ€ ๋งŒ์•ฝ ํ•˜๋‚˜์˜ API๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ API ํ˜ธ์ถœ์˜ ๊ฐ’์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ทธ๊ฑฐ ๋˜ํ•œ ๋‹จ์ˆœํ™” ์‹œ์ผœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// before
const [data1, setData1] = useState();
const [data2, setData2] = useState();

useEffect(()=>{
  getServerData().then((results)=>{
    setData1(results[0]);
  })
},[]);

useEffect(()=>{
  if(data1){
    getAfterData(data1).then((dataList)=>{
      setState2(dataList);
    })
  }
},[data1]);

// after
const { data: data1 } = useQuery(["data1"], getServerData);
const { data: data2 } = useQuery(["data2", data1], getServerData, {
  enabled: !!data1
});

data1์ด๋ผ๋Š” ๋ฐ์ดํ„ฐ์˜ ์กด์žฌ๋ฅผ useEffect์™€ if๋กœ ํ™•์ธํ•˜๋Š” ๋Œ€์‹  react query์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ต์…˜์ค‘ enabled๋ผ๋Š” ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๋งŒ API๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์ด ์™ธ์—๋„ ๋งŽ์€ ์žฅ์ ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • Caching์„ ํ†ตํ•ด์„œ API ์ฝœ๊ณผ ์„œ๋ฒ„์— ๋Œ€ํ•œ ๋ถ€๋‹ด์„ ์ค„์—ฌ์คŒ์œผ๋กœ์จ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์†๋„๋ฅผ ๋†’์—ฌ์ค๋‹ˆ๋‹ค.
  • ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋™์ผ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ค‘๋ณต ์š”์ฒญ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  • ๋น„๋™๊ธฐ ๊ณผ์ •์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๋ž˜ ๋˜์—ˆ๋‹ค๊ณ  ํŒ๋‹จ๋ ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๋Š” ์‹œ์Šคํ…œ์ด ์ง€์›๋ฉ๋‹ˆ๋‹ค.
  • React Hooks์™€ ์œ ์‚ฌํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๊ธฐ์— React๋ฅผ ์ฃผ๋กœ ์ผ๋˜ ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒ ์ง„์ž…์žฅ๋ฒฝ์ด ๋‚ฎ์Šต๋‹ˆ๋‹ค.

React Query ๊ธฐ๋ณธ ์„ค์น˜ ๋ฐ ์„ธํŒ…

npm i @tanstack/react-query

React Query๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” QueryClient ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ๋“ค์ด๋‚˜ app ์ „์ฒด๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก QueryClientProvider๋กœ ๊ฐ์‹ธ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ client prop์œผ๋กœ QueryClient๋ฅผ ๋„˜๊ฒจ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

root.render(
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
);