1. useQuery select option

쿼리 함수에서 반환되는 데이터를 필터링하여 원하는 데이터로 변환해주는 옵션입니다.

리액트 쿼리는 select 함수의 비교를 통해 데이터가 변경되거나 함수가 변경된 경우에만 select 함수를 실행합니다. 마지막으로 검색한 데이터와 동일한 데이터이고 select 함수에도 변동이 없으면 select 함수를 재실행하지 않는 것이 React Query의 최적화입니다. select 함수의 안정적인 비교를 위해서는 useCallback를 사용해야합니다. 그 이유는 컴포넌트가 리렌더링 될 때마다 함수가 재생성되기 때문에 리액트 쿼리에서 select 함수를 제대로 비교할 수 없기 때문입니다.

select option 사용 예시 코드

아래코드는 selection 옵션을 이용하여 filter를 만든 예시코드입니다.

completed를 기준으로 필터 처리를 하였습니다.

Todos.js

import { Suspense, useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { addTodo } from "../api";
import TodoList from "./TodoList";

export default function Todos() {
  const [newTodo, setNewTodo] = useState("");
  const [filter, setFilter] = useState("");
  const queryClient = useQueryClient();

  const { mutate, isPending } = useMutation({
    mutationFn: (newTodo) => addTodo(newTodo),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["todos"] });
    },
    onError: (err) => {
      console.error(err);
    },
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    mutate(newTodo);
    setNewTodo("");
  };

  const selectedFilter = (e) => {
    setFilter(e.target.value);
  };

  return (
    <div>
      <select value={filter} onChange={selectedFilter}>
        <option value="">==Completed==</option>
        <option value="YES">YES</option>
        <option value="NO">NO</option>
      </select>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={newTodo}
          onChange={(e) => setNewTodo(e.target.value)}
          placeholder="Add new todo"
        />
        <button type="submit" disabled={isPending}>
          {isPending ? "Adding..." : "Add"}
        </button>
      </form>
      <Suspense fallback={<p>loading...</p>}>
        <TodoList filter={filter} />
      </Suspense>
    </div>
  );
}

TodoList.js

import { useQuery } from "@tanstack/react-query";
import { fetchTodos } from "../api";
import { useCallback } from "react";

export default function TodoList({ filter }) {
	// filter를 기준으로 데이터 필터링
  // 리렌더링시 재생성 되지 않도록 useCallback 사용
  const selectOption = useCallback((todos) => {
      switch (filter) {
        case "YES":
          return todos.filter((todo) => todo.completed === true);
        case "NO":
          return todos.filter((todo) => todo.completed === false);
        default:
          return todos;
      }
    },[filter]);
  
  const { data: todos, isError } = useQuery({
    queryKey: ["todos"],
    queryFn: fetchTodos,
    select: useCallback((todos)=> selectOption(todos),[selectOption]),
  });

  if (isError) return <p>Something went wrong...</p>;

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>
          <div>No : {todo.id}</div>
          <div>Todo : {todo.title}</div>
          <div>Completed : {todo.completed ? "Y" : "N"}</div>
        </li>
      ))}
    </ul>
  );
}

2. Refetch

refetch는 특정 쿼리의 데이터를 강제로 다시 가져오는 작업을 의미합니다.

refetch가 일어나는 경우

백그라운드에서 자동으로 refetch하는 경우 : React-Query는 백그라운드에서 주기적으로 쿼리를 refetch하는 기능을 제공합니다. 이는 stale time이라는 설정을 통해 제어할 수 있으며, 이를 통해 항상 최신의 데이터를 유지할 수 있습니다.