Front-end/React

[React] React Query: ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ๋ž‘ํ•˜๋Š” ๋ฆฌ์•กํŠธ ๊ฐœ๋ฐœ์ž์˜ ํ•„์ˆ˜ํ…œ ๐Ÿ’–

xeunnie 2025. 1. 6. 01:00
728x90
๋ฐ˜์‘ํ˜•

React Query ํ†บ์•„๋ณด๊ธฐ! ๐Ÿ’–

React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ์ผ์€ ๋งค์ผ์˜ ์ˆ™๋ช… ๊ฐ™์€ ์ผ์ด์ฃ . ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ์บ์‹ฑํ•˜๊ณ , ๊ฐฑ์‹ ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ๋จธ๋ฆฌ๊ฐ€ ์•„ํ”Œ ๋•Œ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋Ÿฐ ๋ฐ˜๋ณต๋˜๋Š” ์ž‘์—…์„ โ€œ๊น”๋”ํ•˜๊ฒŒโ€ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ์นœ๊ตฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ React Query! ๐ŸŽ‰

 

React Query๋Š” ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ์™€ ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” API ํ†ต์‹ ์˜ ๋ณต์žก์„ฑ์„ ํฌ๊ฒŒ ์ค„์—ฌ์ค๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ React Query์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ๊ณผ ํ™œ์šฉ ๋ฐฉ๋ฒ•์„ ๋‚ฑ๋‚ฑ์ด ํŒŒํ—ค์ณ ๋ณผ๊ฒŒ์š”.


๐ŸŒŸ React Query๋ž€?

React Query๋Š” ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  1. ๋ฐ์ดํ„ฐ fetching: ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์บ์‹ฑํ•ฉ๋‹ˆ๋‹ค.
  2. ์ž๋™ ๊ฐฑ์‹ : ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ์ƒˆ๋กœ๊ณ ์นจํ•ฉ๋‹ˆ๋‹ค.
  3. ์˜ค๋ฅ˜ ๊ด€๋ฆฌ: ์š”์ฒญ์ด ์‹คํŒจํ–ˆ์„ ๋•Œ ์žฌ์‹œ๋„ ๋กœ์ง์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  4. ์บ์‹ฑ: ๋™์ผํ•œ ์š”์ฒญ์— ๋Œ€ํ•ด ์บ์‹œ๋ฅผ ์ œ๊ณตํ•ด ๋„คํŠธ์›Œํฌ ๋ถ€๋‹ด์„ ์ค„์ž…๋‹ˆ๋‹ค.
  5. ์ƒํƒœ ๊ด€๋ฆฌ ํ†ตํ•ฉ: ๋กœ๋”ฉ ์ƒํƒœ, ์„ฑ๊ณต ์—ฌ๋ถ€, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ„๋‹จํžˆ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

React Query๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, โ€œ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ -> ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ -> ์„ฑ๊ณต ๋ฐ ์‹คํŒจ ์ฒ˜๋ฆฌโ€๋ผ๋Š” ์ „ํ˜•์ ์ธ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๋” ๊ฐ„๋‹จํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿš€ React Query์˜ ์ฃผ์š” ํŠน์ง•

1. ์ž๋™ ์บ์‹ฑ

React Query๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ๋•Œ ์ž๋™์œผ๋กœ ์บ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์š”์ฒญํ•˜๋ฉด ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

2. ์ž๋™ ๋ฆฌํŽ˜์น˜(Auto Refetch)

๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ(ํƒญ ํฌ์ปค์Šค, ๋„คํŠธ์›Œํฌ ์žฌ์—ฐ๊ฒฐ ๋“ฑ), React Query๋Š” ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ฉ๋‹ˆ๋‹ค.

 

3. ์ฟผ๋ฆฌ ์žฌ์‹œ๋„

๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์‹คํŒจํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ 3๋ฒˆ ์žฌ์‹œ๋„ํ•˜๋ฉฐ, ์žฌ์‹œ๋„ ๊ฐ„๊ฒฉ๋„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

4. ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ

React Query๋Š” ์„œ๋ฒ„ ์ƒํƒœ์™€ ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•˜์—ฌ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. Redux๋‚˜ MobX ๊ฐ™์€ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€๋„ ์‰ฝ๊ฒŒ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


โ›ฒ๏ธ ์„ค์น˜ ๋ฐฉ๋ฒ•

React Query๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”:

npm install @tanstack/react-query
npm install @tanstack/react-query-devtools

 

React Query์˜ ๊ฐœ๋ฐœ ๋„๊ตฌ๋„ ํ•จ๊ป˜ ์„ค์น˜ํ•˜๋ฉด ๋””๋ฒ„๊น…์ด ํ›จ์”ฌ ํŽธ๋ฆฌํ•ด์ง‘๋‹ˆ๋‹ค. DevTools๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ ์ƒํƒœ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.


๐Ÿ›ธ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

1. React Query ํด๋ผ์ด์–ธํŠธ ์„ค์ •

๋จผ์ €, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ตœ์ƒ์œ„์— QueryClientProvider๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <MyComponent />
    </QueryClientProvider>
  );
}

export default App;

 

2. ๋ฐ์ดํ„ฐ fetching ์˜ˆ์ œ

useQuery ํ›…์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๋กœ๋”ฉ ์ƒํƒœ์™€ ์˜ค๋ฅ˜๋ฅผ ๊ฐ„๋‹จํžˆ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

function MyComponent() {
  const { data, isLoading, isError } = useQuery(["todos"], fetchTodos);

  if (isLoading) return <p>Loading...</p>;
  if (isError) return <p>Error occurred!</p>;

  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

async function fetchTodos() {
  const response = await fetch("https://jsonplaceholder.typicode.com/todos");
  if (!response.ok) throw new Error("Network response was not ok");
  return response.json();
}

๐Ÿ„๐Ÿปโ€โ™€๏ธ React Query์˜ ์ƒํƒœ์™€ ๋ผ์ดํ”„์‚ฌ์ดํด

React Query๋Š” ๋ฐ์ดํ„ฐ์˜ ์ƒํƒœ๋ฅผ ํฌ๊ฒŒ 3๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค:

  1. isLoading: ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜์Œ ๊ฐ€์ ธ์˜ค๋Š” ์ƒํƒœ.
  2. isError: ์š”์ฒญ์ด ์‹คํŒจํ•œ ์ƒํƒœ.
  3. isSuccess: ๋ฐ์ดํ„ฐ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ€์ ธ์™€์ง„ ์ƒํƒœ.

์ด ์™ธ์—๋„ isFetching(๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ), isIdle(์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์€ ์ƒํƒœ) ๋“ฑ์˜ ์ƒํƒœ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


๐Ÿง—๐Ÿปโ€โ™€๏ธ React Query์˜ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ

1. ์ฟผ๋ฆฌ ๋ฌดํšจํ™”(Query Invalidations)

๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ ํ›„ ๊ธฐ์กด ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํšจํ™”ํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { useMutation, useQueryClient } from "@tanstack/react-query";

function AddTodo() {
  const queryClient = useQueryClient();
  const mutation = useMutation(addTodo, {
    onSuccess: () => {
      queryClient.invalidateQueries(["todos"]); // todos ์ฟผ๋ฆฌ ๋ฌดํšจํ™”
    },
  });

  return (
    <button onClick={() => mutation.mutate({ title: "New Todo" })}>
      Add Todo
    </button>
  );
}

 

2. Optimistic Update

์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋” ๋น ๋ฅด๊ฒŒ ๋ฐ˜์‘ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

const mutation = useMutation(addTodo, {
  onMutate: async (newTodo) => {
    await queryClient.cancelQueries(["todos"]);
    const previousTodos = queryClient.getQueryData(["todos"]);
    queryClient.setQueryData(["todos"], (old) => [...old, newTodo]);
    return { previousTodos };
  },

  onError: (err, newTodo, context) => {
    queryClient.setQueryData(["todos"], context.previousTodos);
  },

  onSettled: () => {
    queryClient.invalidateQueries(["todos"]);
  },
});

 

3. React Query DevTools

๊ฐœ๋ฐœ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฟผ๋ฆฌ์˜ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

<QueryClientProvider client={queryClient}>
  <App />
  <ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>;

โš ๏ธ React Query๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 

1. ์บ์‹œ ์‹œ๊ฐ„๊ณผ ๊ฐฑ์‹  ์ „๋žต์„ ์ ์ ˆํžˆ ์„ค์ •

์บ์‹œ๊ฐ€ ์˜ค๋ž˜ ์œ ์ง€๋˜๋ฉด ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๊ณ , ๋„ˆ๋ฌด ์ž์ฃผ ๊ฐฑ์‹ ํ•˜๋ฉด ๋„คํŠธ์›Œํฌ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

2. ๋ฐ์ดํ„ฐ์˜ ์˜์กด์„ฑ ๊ด€๋ฆฌ

์ฟผ๋ฆฌ ํ‚ค๋ฅผ ๋ช…ํ™•ํžˆ ์„ค์ •ํ•˜์—ฌ, ์˜๋„ํ•˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์„ ๋ฐฉ์ง€ํ•˜์„ธ์š”.

 

3. ๋ฐฑ์—”๋“œ์™€ ํ˜‘๋ ฅ ํ•„์š”

React Query๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋ฏ€๋กœ, ํšจ์œจ์ ์ธ API ์„ค๊ณ„๊ฐ€ ํ•จ๊ป˜ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ”– ๊ฒฐ๋ก 

React Query๋Š” ๋ณต์žกํ•œ ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ fetching, ์บ์‹ฑ, ๊ฐฑ์‹ ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋‹ˆ, ์—ฌ๋Ÿฌ๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋” ํšจ์œจ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋  ๊ฑฐ์˜ˆ์š”. ์ฒ˜์Œ์—” ์กฐ๊ธˆ ๋‚ฏ์„ค ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•œ ๋ฒˆ ์ต์ˆ™ํ•ด์ง€๋ฉด ๋Œ์•„๊ฐ€๊ธฐ ํž˜๋“ค ๊ฑฐ๋ž๋‹ˆ๋‹ค. ๐Ÿ˜Ž

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น!๐ŸŒท

728x90
๋ฐ˜์‘ํ˜•