React-Query를 이용해 서버 상태 분리하기

Paya·2024년 4월 11일

Dansup 프로젝트

목록 보기
4/6
post-thumbnail

프로젝트로 진행한 'Dansup' 서비스는 댄서들을 위한 통합 정보 플랫폼이다.
정보 플랫폼인 만큼 최대한 사용자 맞춤형 정보를 제공하기 위해, 댄스 수업 정보의 필터링 기능을 다음과 같이 4가지 경우로 나누어 구현하였다.

  • 아무것도 적용하지 않은 경우, 전체 댄스 수업을 제공
  • 필터를 적용한 경우, 필터링된 댄스 수업을 제공
  • 검색창에 검색어를 입력한 경우, 필터링된 댄스 수업을 제공
  • 검색어를 입력한 후에, 필터까지 함께 적용한 경우, 필터링된 댄스 수업을 제공

위와 같이 4가지 경우 모두 서버에서 데이터를 불러오는 코드를 작성해야 한다.
이러한 코드를 작성하기 위해서는 불러온 서버 데이터로 값을 업데이트할 클라이언트 상태를 생성하고, useEffect를 이용해 컴포넌트가 Mount될 때 API 호출을 해서 서버에서 데이터를 불러와 클라이언트 상태의 값을 업데이트해줘야 한다.

🔺 하지만 이러한 방식으로 코드를 작성할 경우, 다음과 같은 문제점이 있다...!
1. 클라이언트 상태와 서버 상태가 명확히 구분되지 않는다.
2. 상태마다 작성해줘야 하는 useEffect 때문에 흐름 파악이 어렵다.
3. 개발자마다 개개인의 방식대로 서버에서 데이터를 불러오는 코드를 작성하기 때문에, 협업 시에 코드를 이해하는 데에 어려움을 준다.


✨ 그래서 "React-Query"를 사용하기로 결정했다...!

React-Query는 React Application에서 API 요청 및 서버 상태를 효율적으로 관리해주는 라이브러리이다.

React-Query를 이용하면 다음과 같이 개선될 수 있다!
1. 서버 상태를 클라이언트 상태와 분리하여 관리할 수 있어 직관적이고 효율적이다.
2. 상태마다 useEffect를 작성할 필요가 없어져 흐름 파악이 쉬워진다.
3. 규격화된 방식으로 코드를 작성하기 때문에, 협업 시에 효율성이 높아진다.
4. 캐싱 등의 다양한 기능을 이용할 수 있다.


프로젝트에서 React-Query를 이용해 필터링 기능을 직접 구현한 코드를 보기 전에,
React-Query에서 사용되는 Hook 2가지에 대해서 간단히 알아보자.

useQuery

👉 서버에서 데이터를 불러올 때 사용되는 Hook

예시 코드) 서버로부터 todo 리스트를 불러오는 코드

import { useQuery } from '@tanstack/react-query'
import { getTodos } from '../my-api'

function Todos() {
  const { data } = useQuery({
    queryKey: ['todos'],
    queryFn: getTodos,
  })
}
  • queryKey를 통해 데이터 캐싱을 관리한다.
  • queryFn은 Promise를 리턴하는 함수로, 이곳에 API 호출 함수를 작성한다.
  • data는 서버로부터 받아온 데이터이다.

useMutation

👉 서버의 데이터를 생성, 변경, 삭제할때 사용되는 Hook

예시 코드) 서버에 새로운 todo를 추가하는 코드

import { useMutation } from '@tanstack/react-query'
import { postTodo } from '../my-api'

function Todos() {
  const mutation = useMutation({
    mutationFn: postTodo,
  })

  return (
    <button
      onClick={() => {
        mutation.mutate({ id: new Date(), title: 'Do Laundry' })
      }}
    >
      Add Todo
    </button>
  )
}
  • mutationFn은 Promise를 리턴하는 함수로, 이곳에 API 호출 함수를 작성한다.
  • mutate 함수를 호출하여 variables를 mutationFn에 전달하고, mutationFn을 실행시킬 수 있다.

프로젝트에서 React-Query를 이용해 필터링 기능을 직접 구현한 코드는 다음과 같다!
필터의 ON/OFF 여부에 따라, 서버로부터 해당되는 데이터를 불러오도록 구현하였다.
(필터링 기능을 구현할 때는 서버로부터 데이터를 불러오기만 할 것 이므로, useMutation hook은 사용하지 않고, useQuery hook만 사용하였다.)

홈 페이지에서,

  • 아무것도 적용하지 않은 경우, '전체 수업 조회 api'를 호출하여 서버로부터 전체 수업 데이터 불러오기
  • 필터를 적용한 경우, 필터 값(filterValue)과 함께 '필터링 적용한 수업들 조회 api'를 호출하여 서버로부터 필터링된 수업 데이터 불러오기
import { useQuery } from '@tanstack/react-query';
import { getAllClassList(전체 수업 조회 api 호출 함수), getFilteredClassList(필터링 적용한 수업들 조회 api 호출 함수) } from '@/apis/class';


function HomePage() {
  
    const { data: classList } = useQuery(
        !isFilterOn ? ['classList'] : ['classList', filterValue],
        !isFilterOn
        	? getAllClassList
        	: () => getFilteredClassList({
                searchWord: null, //검색어는 없으니 null
                filterValue: filterValue,
              }),
    );
  
}

검색 결과 페이지에서,

  • 검색창에 검색어를 입력한 경우, 검색어(searchWord)와 함께 '필터링 적용한 수업들 조회 api'를 호출하여 서버로부터 필터링된 수업 데이터 불러오기
  • 검색어를 입력한 후에, 필터까지 함께 적용한 경우, 검색어(searchWord),필터 값(filterValue)과 함께 '필터링 적용한 수업들 조회 api'를 호출하여 서버로부터 필터링된 수업 데이터 불러오기
import { useQuery } from '@tanstack/react-query';
import { getFilteredClassList(필터링 적용한 수업들 조회 api 호출 함수) } from '@/apis/class';


function SearchResultPage() {
  
  	const { searchWord } = router.query; //url의 쿼리스트링에서 검색어 가져오기
  
    const { data: classList } = useQuery(
        !isFilterOn ? ['classList', searchWord] : ['classList', filterValue],
        () => getFilteredClassList({
            searchWord: searchWord, 
            filterValue: !isFilterOn ? {} : filterValue, //필터 값이 없을 경우, {}
        }),
    );
  
}

0개의 댓글