RTK Query는 강력한 data fetching & caching 도구입니다. 웹 어플리케이션의 기본적이며 공통적인 데이터 로딩 작업을 단순화 시켜주며, 개발자가 data fetching, caching과 관련된 로직을 직접 작성하지 않도록 도와줍니다.

Motivation

웹 어플리케이션은 화면에 특정 데이터를 표시하기 위해 서버에서 데이터를 fetch 해야 합니다. 그리고 데이터에 대한 update 작업과 update된 내용을 서버에 전달하는 작업, 클라이언트측에서 server의 data와 sync가 맞는 캐싱 데이터 유지 작업 등이 필요합니다. 이는 오늘날의 애플리케이션에서 사용되는 다른 동작을 구현해야 하기 때문에 더욱 복잡해집니다.

  • Tracking loading state in order to show UI spinner
  • Avoiding duplicate requests for the same data
  • Optimistic updates to make the UI feel faster
  • Managing cache lifetimes as the user interacts with the UI

"data fetching and caching"은 단순한 "state management"와 다른 관심사를 갖고 있습니다. Redux와 같은 state management library를 cache data 구현에 사용하기도 하지만, use cases 들이 너무 다르며, data fetching use case에 목적을 둔 도구가 필요합니다.

RTK Query는 Apollo Client, React Query, Urql, SWR 등 data fetching에 목적을 둔 솔루션에서 영감을 받았지만, API design에 유니크한 접근을 더했습니다.

  • data fetching, caching 로직은 Redux Toolkit의 createSlice및 createAsyncThunk API를 기반으로 구축됩니다.
  • Redux Toolkit은 UI에 구애받지 않기 때문에 RTK Query의 기능은 모든 UI 계층에서 사용할 수 있습니다.
  • API endpoint는 인수에서 쿼리 매개변수를 생성하고 캐싱을 위해 응답을 변환하는 방법을 포함하여 미리 정의됩니다.
  • RTK Query는 전체 data fetching 작업을 캡슐화한 React hooks를 생성하며, data, isFetching 필드를 컴포넌트에 제공하고, 컴포넌트의mount, unmount에 따른 chached data의 lifetime을 관리합니다.
  • RTK Query는 initial data fetching 이후 websocket message를 통한 스트림 캐시 업데이트와 같은 use case를 위해 "cache entry lifecycle" 옵션을 제공합니다.
  • OpenAPI 및 GraphQL 스키마에서 API 슬라이스의 코드 생성에 대한 초기 작업 예가 있습니다.
  • RTK Query는 TypeScript로 작성되었으며, 완벽한 TS usage를 제공하도록 디자인 되었습니다.

What's included

RTK Query는 핵심 Redux Toolkit 패키지 설치에 포함되어 있습니다. 아래 두 진입점 중 하나를 통해 사용할 수 있습니다.

import { createApi } from '@reduxjs/toolkit/query'

/* React-specific entry point that automatically generates
   hooks corresponding to the defined endpoints */
import { createApi } from '@reduxjs/toolkit/query/react'

RTK Query는 다음과 같은 API를 포함합니다.

  • createApi(): RTK Query 기능의 코어입니다. data fetching 및 변환에 대한 설정을 포함하여 일련의 endpoints에서 data를 어떻게 가져올지 describe하는 일련의 endpoints를 정의할 수 있도록 해줍니다. 대부분의 경우, "base URL당 하나의 API slice"를 rule of thumb로 하여 이 api를 어플리케이션당 한 번 사용해야 합니다.
  • fetchBaseQuery(): 요청을 단순화하는 것을 목표로 하는 작은 Wrapper. 대부분의 사용자가 createApi에서 사용하도록 권장되는 baseQuery로 의도되었습니다.
  • ApiProvider: Redux store가 없는 경우 Provider로 사용될 수 있습니다.
  • setupListeners(): refetchOnMount와 refetchOnReconnect 행동과 관련하여 사용할 수 있는 유틸입니다.

Basic Usage

Create an API Slice

React에서 사용하는 경우, createApi를 import해 server의 base URL과 어떤 endpoint와 상호작용할지 나열해 놓은 "API slice"를 정의하는 것으로 시작합니다.

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

// Define a service using a base URL and expected endpoints
export const pokemonApi = createApi({
  reducerPath: 'pokemonApi',
  baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
  endpoints: (builder) => ({
    getPokemonByName: ({
      query: (name) => `pokemon/${name}`,
    }),
  }),
})

// Export hooks for usage in functional components,
// which are auto-generated based on the defined endpoints
export const { useGetPokemonByNameQuery } = pokemonApi

Configure the Store

"API slice"는 자동 생성된 Redux slice reducer와 구독 수명을 관리하는 커스텀 미들웨러를 포함하고 있습니다. 둘 다 Redux store에 추가되어야 합니다.

import { configureStore } from '@reduxjs/toolkit'
// Or from '@reduxjs/toolkit/query/react'
import { setupListeners } from '@reduxjs/toolkit/query'
import { pokemonApi } from './services/pokemon'

export const store = configureStore({
  reducer: {
    // Add the generated reducer as a specific top-level slice
    [pokemonApi.reducerPath]: pokemonApi.reducer,
  },
  // Adding the api middleware enables caching, invalidation, polling, and other useful features of 'rtk-query'
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(pokemonApi.middleware),
})

// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see 'setupListeners' docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch)

Use Hooks in Components

마지막으로 컴포넌트 파일에 API slice로 부터 자동으로 생성된 React hooks를 import하고, 필요한 parameter와 함께 컴포넌트에서 호출합니다. RTK Query는 on mount시 자동으로 data를 가져오고, parameter가 변할 때 마다 re-fetch해주며, {data, isFetching}을 결과로 제공해주고, 값들이 변화할 때 마다 re-render 해줍니다.

import * as React from 'react'
import { useGetPokemonByNameQuery } from './services/pokemon'

export default function App() {
  // Using a query hook automatically fetches data and returns query values
  const { date, error, isLoading } = useGetPokemonByNameQuery('bulbasaur')
  // Individual hooks are also accessible under the generated endpoints:
  // const { data, error, isLoading } = pokemonApi.endpoints.getPokemonByName.useQuery('bulbasaur')
  
  // render UI based on data and loading state
}

출처

profile
웹 개발을 공부하고 있는 윤석주입니다.

0개의 댓글