๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
React

[React] react-query, ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 

by LasBe 2023. 4. 16.
๋ฐ˜์‘ํ˜•

๐Ÿ“’ react-query๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 


๋ฆฌ์•กํŠธ์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ฌด์ˆ˜ํžˆ ๋งŽ์Šต๋‹ˆ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ redux, recoil ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๋Š”๋ฐ,
๋Œ€๋ถ€๋ถ„ ์ด๋Ÿฌํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ
ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ์™€ ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ํ•จ๊ป˜ ๋‹ด์•„๋‘๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ด๊ณ , ๋˜ ๊ทธ๋Ÿด ์ˆ˜ ๋ฐ–์— ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

 

react-query๋ฅผ ์‚ฌ์šฉํ•ด ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—
์ง๊ด€์ ์ด๊ณ  ํšจ์œจ์ ์ธ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

 

์ด ์™ธ์—๋„ react-query์—์„œ ์ง€์›ํ•˜๋Š” ๋‹ค์–‘ํ•œ ์˜ต์…˜๋“ค์„ ์‚ฌ์šฉํ•ด
์บ์‹ฑ, ์—๋Ÿฌ์ฒ˜๋ฆฌ, suspense, refresh, data fetching ์กฐ๊ฑด ์„ค์ • ๋“ฑ๋“ฑ
๊ธฐ์กด์— ๋ถˆํŽธํ•˜๊ฒŒ ๋Š๊ผˆ๋˜ ๋ถ€๋ถ„๋“ค์„ ์„ ์–ธ์ ์ด๊ณ  ๊ฐ„ํŽธํ•˜๊ฒŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ react-query๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ˆ„๋ฆด ์ˆ˜ ์žˆ๋Š” ์ด์ ๋“ค์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


์ƒˆ๋กญ๊ฒŒ ์—…๋ฐ์ดํŠธ ๋œ react-query v5 ๋ฒ„์ „์— ๊ด€ํ•œ ๋‚ด์šฉ๋“ค์„ ๋น ๋ฅด๊ฒŒ ์•Œ์•„๋ณด๊ณ  ์‹ถ์œผ๋ฉด ๋‹ค์Œ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!

react-query v5 ์ฃผ์š” ๋ณ€๊ฒฝ์  ์•Œ์•„๋ณด๊ธฐ feat. Suspense, ErrorBoundary


๐Ÿ“Œ Data Fetching ๋กœ์ง ๋‹จ์ˆœํ™”

๊ธฐ์กด์— ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. Fetching ์ฝ”๋“œ ์ž‘์„ฑ
  2. ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ ๋‘˜ ์ƒํƒœ ์ƒ์„ฑ
  3. useEffect๋ฅผ ์ด์šฉํ•ด ์ปดํฌ๋„ŒํŠธ Mount์‹œ ๋ฐ์ดํ„ฐ๋ฅผ Fetching ํ•œ ๋’ค ์ƒํƒœ์— ์ €์žฅ
import { useEffect, useState } from "react";

const getServerData = async () => {
  const data = await fetch(
    "https://jsonplaceholder.typicode.com/posts"
  ).then((response) => response.json());
  return data;
};

export default function App() {
  const [state, setState] = useState<any[]>([]);

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

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

 

์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ react-query๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

import { useQuery } from "@tanstack/react-query";

const getServerData = async () => {
  const data = await fetch(
    "https://jsonplaceholder.typicode.com/posts"
  ).then((response) => response.json());
  return data;
};

export default function App() {
  const { data } = useQuery(["data"], getServerData);

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

์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์„ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค๊ณ  useEffect๋กœ ์ƒํƒœ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ๋ชจ๋“  ๊ณผ์ •์„
useQuery ๋‹จ ํ•œ์ค„๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์žฅ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

๐Ÿ”Ž ์ฝ”๋“œ ์ˆ˜ ๊ฐ์†Œ

์ผ๋ฐ˜์ ์ธ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •์˜ ์ฝ”๋“œ๊ฐ€ ๊ทธ๋ž˜๋„ ์–ผ๋งˆ ์•ˆ๋˜๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ฒ ์ง€๋งŒ
๋ฐ›์•„ ์˜ฌ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ์— ๋น„๋ก€ํ•ด์„œ ์ถ”๊ฐ€๋˜๋Š” ์ƒํƒœ์™€ Side Effect๋ฅผ ์ƒ๊ฐํ•˜๋ฉด ๊ต‰์žฅํžˆ ๊ฐ•๋ ฅํ•œ ์žฅ์ ์ž…๋‹ˆ๋‹ค.

 

๐Ÿ”Ž Side Effect ์ œ๊ฑฐ

ํŠนํžˆ๋‚˜ ์ƒํƒœ๋งˆ๋‹ค ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” useEffect๋ฅผ ๊ฑท์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€
์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋กœ ๋ฐœ์ƒํ•˜๋Š” ์žฅํ™ฉํ•œ Side Effect๋กœ ์ธํ•ด ํ๋ฆ„ ํŒŒ์•…์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค์—ˆ๋˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ”Ž Data Fetching ๋ฐฉ์‹ ๊ทœ๊ฒฉํ™”

์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•์— ๋ช…ํ™•ํ•œ ์ •๋‹ต์€ ์—†๊ธฐ ๋•Œ๋ฌธ์—
๊ฐœ๋ฐœ์ž๋“ค๋งˆ๋‹ค ๊ฐœ๊ฐœ์ธ์˜ ๋ฐฉ์‹๋Œ€๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ œ๊ฐ๊ฐ์œผ๋กœ useEffect๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ
์ž์‹ ์ด ์ง  ์ฝ”๋“œ๋ผ๋„ ์ „์ฒด์ ์ธ ํ๋ฆ„์„ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ์‰ฝ์ง€ ์•Š์•˜๊ณ ,
๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ์ˆ˜์ •ํ•˜๋Š” ์ผ์€ ๋”์šฑ๋” ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ react-query๊ฐ€ ๋‚ด์žฅ๋œ ๊ธฐ๋Šฅ์œผ๋กœ ๊ด€๋ จ ๋กœ์ง๋“ค์„ ์ „๋ถ€ ์ฒ˜๋ฆฌํ•ด์ฃผ๋‹ˆ
์ง€์›ํ•˜๋Š” ํ›…์„ ์ด์šฉํ•ด ๋ชจ๋‘๊ฐ€ ํš์ผํ™” ๋œ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ๋™๊ธฐ์  ์‹คํ–‰

์–ด๋– ํ•œ API๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ API์˜ ๊ฐ’์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„ฃ์–ด์ค˜์•ผ๋  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„  ๋™๊ธฐ์ ์œผ๋กœ API๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

const [state1, setState1] = useState();
const [state2, setState2] = useState();

useEffect(()=>{
  getServerData().then((dataList)=>{
    setState1(dataList[0]);
  })
},[]);

// state1์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„ฃ์–ด ํ˜ธ์ถœํ•˜๋Š” API
useEffect(()=>{
  if(state1){
    getAfterData(state1).then((dataList)=>{
      setState2(dataList);
    })
  }
},[state1]);

 

๊ฐ„๋žตํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด๋ดค๋Š”๋ฐ๋„ ์ฝ”๋“œ์–‘์ด ๋งŽ์Šต๋‹ˆ๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ API ํ˜ธ์ถœ์„ ์œ„ํ•œ ์กฐ๊ฑด๋„ ์ถ”๊ฐ€๋˜์–ด ๋™๊ธฐ์ ์œผ๋กœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๊ณ ,
useEffect์˜ ์ˆœ์„œ๊ฐ€ ๋‹ค๋ฅธ ์ฝ”๋“œ๋“ค๊ณผ ์„ž์ธ๋‹ค๋ฉด
์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ์–ธ์ œ, ์–ด๋–ป๊ฒŒ ํ˜ธ์ถœ ๋˜๋Š”์ง€ ํ๋ฆ„๊ณผ ์‹œ์ ์„ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.

 

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

react-query ์˜ต์…˜ ์ค‘ enabled ์€ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๋งŒ API๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜์–ด
์œ„์™€ ๊ฐ™์ด ์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ API๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ์บ์‹ฑ

ํ›…์„ ํ˜ธ์ถœํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ์˜ ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • staletime
    ํ˜ธ์ถœํ•œ ๋ฐ์ดํ„ฐ๋Š” ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ ์ž์ฒด์ ์œผ๋กœ ์ €์žฅ์„ ํ•ด๋‘ก๋‹ˆ๋‹ค.
    staletime์€ ์ด ์บ์‹œ๋ฐ์ดํ„ฐ์˜ ์œ ํ†ต๊ธฐํ•œ์„ ์ •ํ•ด์ฃผ๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค.
    default๋Š” 0์œผ๋กœ, ๋ณ„๋‹ค๋ฅธ ์˜ต์…˜ ์„ธํŒ…์„ ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด
    ๋ฐ์ดํ„ฐ๊ฐ€ staleํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • cachetime
    cashetime์€ ์ €์žฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์–ผ๋งˆ๋‚˜ ์œ ์ง€ํ• ์ง€ ์ •ํ•ด์ฃผ๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค.
    default๋Š” 5๋ถ„์ž…๋‹ˆ๋‹ค.
const { data } = useQuery(['data', getServerData,{
  staletime: 10 * 60 * 1000;
  cashetime: 10 * 60 * 1000;
})

์œ„์™€ ๊ฐ™์ด ์˜ต์…˜์„ ์ง€์ •ํ•ด์ฃผ๋ฉด ๋ณ„๋‹ค๋ฅธ refresh๊ฐ€ ์—†์„ ๋•Œ
10๋ถ„ ๋‚ด ์žฌํ˜ธ์ถœ์‹œ API๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์บ์‹ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค.

 

๐Ÿ“Œ Suspense ์‚ฌ์šฉ

Suspense์— ๊ด€๋ จ๋œ ์ž์„ธํ•œ ์ด์•ผ๊ธฐ๋Š” ์ „์— ์ž‘์„ฑํ•ด๋’€๋˜ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

2023.03.23 - [Web/React] - [React] Suspense์„ ์‚ฌ์šฉํ•ด ์„ ์–ธ์ ์œผ๋กœ ๋กœ๋”ฉ ํ™”๋ฉด ๊ตฌํ˜„ํ•˜๊ธฐ

 

[React] Suspense์„ ์‚ฌ์šฉํ•ด ์„ ์–ธ์ ์œผ๋กœ ๋กœ๋”ฉ ํ™”๋ฉด ๊ตฌํ˜„ํ•˜๊ธฐ

โšก React Suspense ๋ฆฌ์•กํŠธ์˜ Suspense๋Š” React 16 ๋ฒ„์ „์—์„œ ์ฒ˜์Œ์œผ๋กœ ์„ ๋ณด์ธ ํ›„ 18 ๋ฒ„์ „์œผ๋กœ ์˜ค๋ฉฐ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” React 18์—์„œ์˜ Suspense๋ฅผ ์™œ, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. โšก Susp

lasbe.tistory.com

 

๐Ÿ“Œ ๋งˆ๋ฌด๋ฆฌ

์ œ๊ฐ€ ์ƒ๊ฐํ•˜๊ธฐ์— ๊ฐ€์žฅ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ์‹ถ์€ ๊ธฐ๋Šฅ๋“ค ์œ„์ฃผ๋กœ ์„ค๋ช…ํ•ด๋ดค์ง€๋งŒ
์ด ์™ธ์—๋„ ์—๋Ÿฌ์ฒ˜๋ฆฌ์™€ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ refresh ๋ฐฉ๋ฒ•, data update ๋“ฑ๋“ฑ ๋” ๋งŽ์€ ์žฅ์ ์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์—
๋‹ค์Œ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ˜๋“œ์‹œ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•ด๋ด…๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€


์˜คํ”ˆ ์ฑ„ํŒ