React - Query

최재홍·2023년 4월 29일
0
post-custom-banner

Query

다른 서버와의 API 통신과 비동기 데이터 관리를 위해 Redux-thunk, Redux-Saga등의 미들웨어를 사용할 수 있었으나, 다음의 문제가 있었다.

  1. 코드량이 지나치게 많음
  2. Redux가 비동기 데이터 관리를 위한 전문 라이브러리가 아니기 때문에 규격화의 문제가 있음

하지만 그에 비해 Query는 다음의 장점이 있었다.

  1. 코드량이 적음
  2. 사용방법이 쉽고, 직관적임

주요 키워드

(1)Query

어떤 데이터에 대한 요청을 의미한다.
axios의 경우 get요청과 비슷하다.

(2)Mutation

어떤 데이터의 변경.
어떤 데이터라 함은, 데이터 그룹 그 자체를 의미.
바꾼다는 것은 추가, 수정, 삭제를 위미. CRUD 중, CUD에 해당한다.
axios의 경우 post, put, patch, delete 요청과 비슷하다.

(3)Query Invalidation

Query를 Invalidation 즉, 무효화 시킨다.
기존에 가져온 Query는 서버 데이터이기 때문에, 언제든지 변경이 생길 수 있다. 그렇기 때문에 '최신 상태가 아닐 수' 있다. 그런 경우, 기존 쿼리를 '무효화' 시킨 후 최신화 해야한다.
그 기능을 하는 것이 Query Invalidation이다.

사용법

설치

yarn add react-query

App.jsx)

import React from "react";
import Router from "./shared/Router";
import { QueryClient, QueryClientProvider } from "react-query";

const queryClient = new QueryClient();

const App = () => {

  return (
    <QueryClientProvider client={queryClient}>
      <Router />;
    </QueryClientProvider>
  );
};

export default App;

QueryClientPrivider : 데이터를 읽어오는 기능(QueryClient)을 애플리케이션 전체에 주입하는 API


useQuery를 이용하여 조회기능을 구현해보자. src > api 폴더를 만들어주고 그 아래에 todos관련 api를 관리할 파일을 만들자.

src > api > todos.js

import axios from "axios";

// 모든 todos를 가져오는 api
const getTodos = async () => {
  const response = await axios.get("http://localhost:3000/todos");
  return response;
};

export { getTodos };

TodoList 컴포넌트의 코드도 변경

TodoList.jsx)

import React from "react";
import { StyledDiv, StyledTodoListHeader, StyledTodoListBox } from "./styles";
import Todo from "../Todo";
import { __getTodosThunk } from "../../modules/todosSlice";

import { getTodos } from "../../../api/todos";
import { useQuery } from "react-query";

/**
 * 컴포넌트 개요 : 메인 > TODOLIST. 할 일의 목록을 가지고 있는 컴포넌트
 * 2022.12.16 : 최초 작성
 *
 * @returns TodoList 컴포넌트
 */
function TodoList({ isActive }) {
  const { isLoading, isError, data } = useQuery("todos", getTodos);

  if (isLoading) {
    return <p>로딩중입니다....!</p>;
  }

  if (isError) {
    return <p>오류가 발생하였습니다...!</p>;
  }

  return (
    <StyledDiv>
      <StyledTodoListHeader>
        {isActive ? "해야 할 일 ⛱" : "완료한 일 ✅"}
      </StyledTodoListHeader>
      <StyledTodoListBox>
        {data
          .filter((item) => item.isDone === !isActive)
          .map((item) => {
            return <Todo key={item.id} todo={item} isActive={isActive} />;
          })}
      </StyledTodoListBox>
    </StyledDiv>
  );
}

export default TodoList;

더 나아가기

useQuery

useQuery hook에 대해서 다시 한번 알아보자.

import { useQuery } from 'react-query';
import { fetchTodoList } from '../api/fetchTodoList';

function App() {
	const info = useQuery('todos', fetchTodoList);
}

1. 첫 번째 인자 'todos' 이걸 쿼리의 키(Query Keys)라고 부른다.

  • refetching 하는데 쓰인다
  • 캐싱(chching) 처리를 하는데에도 쓰인다.
  • 애플리케이션 전체 맥락에서 이 쿼리를 공유하는 방법으로 쓰인다. -> 어느 컴포넌트 곳곳에 뿌려져 있어도 같은 key면 같은 쿼리 및 데이터 보장

2. 두 번째 인자, 'fetchTodoList' 이걸 쿼리 함수(Query Function)이라고 부른다.

  • 쿼리 함수는 promise 객체를 return한다.
  • promise 객체는 반드시 data를 resolve하거나 에러를 낸다.

3. useQuery의 결과물

  • useQuery를 통해 얻은 결과물은 객체이다.
  • 그 안에 조회를 요청한 결과에 대한 거의 모든 정보가 들어있고, 그 과정에 대한 정보도 다음과 같이 들어 있다.
  • 함수가 동작하기 시작하면 isLoading이 true가 된다. 조회 결과 오류가 나면 isError가 true가 된다. isLoading은 false가 된다. 조회 결과 정상이 되면 isSuccess가 true가 된다. isLoading은 false가 된다.

mutation

위에서 언급했듯이, query와는 다르게 mutation은 CUD(create, update, delete)에서 사용된다.

ex)

// [출처] : 공식문서

function App() {
   const mutation = useMutation(newTodo => {
     return axios.post('/todos', newTodo)
   })
 
   return (
     <div>
       {mutation.isLoading ? (
         'Adding todo...'
       ) : (
         <>
           {mutation.isError ? (
             <div>An error occurred: {mutation.error.message}</div>
           ) : null}
 
           {mutation.isSuccess ? <div>Todo added!</div> : null}
 
           <button
             onClick={() => {
               mutation.mutate({ id: new Date(), title: 'Do Laundry' })
             }}
           >
             Create Todo
           </button>
         </>
       )}
     </div>
   )
 }

useMutation은 hook이다.

  • mutation.mutate(인자)
    1. 인자는 반드시 한 개의 변수 또는 객체여야 한다.
    2. 인자는 보통 비동기 함수여야 한다.(위의 예시에서는 비동기 함수를 직접 정의해줬고, 직접한 과제에서는 api.js파일에서 export해와서 인자로 담았다.)
  • 결과를 객체 형태로 가지고 있다.
  • 결과 객체는 항상 어느 상태 중 하나에 속한다.(isIdle, isLoading, isError,isSuccess)
post-custom-banner

0개의 댓글