[React Query] react-query 시작하기

apro_xo·2022년 8월 7일
8
post-thumbnail

최근에 react-query에 관심을 갖게 되어 사용법을 공부하면서 실험적으로 사용해봤는데, 잘 작동하지 않았다.

react-query가 최근에 업데이트를 거치면서 install 하는 방법도 바뀌었다. 내가 겪었고, 내가 삽질하며 해결한 것들을 그냥 정말 간략하게 한 번 적어보려 한다.

1. 설치

react-query

npm install @tanstack/react-query

기존에는 npm install react-query 였는데,, 설치 방법도 바뀌었더라!

react-query-devtools

npm install @tanstack/react-query-devtools

기존에는 react-query-devtools를 따로 설치하지 않고 그냥 사용해도 됐었는데, 이제는 위와 같이 설치까지 해줘야 devtools를 사용할 수 있더라.

react-query 적용

index.js에 적용하는 방법을 알아보자.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'

const queryClient = new QueryClient();

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <QueryClientProvider client={queryClient}>
    <ReactQueryDevtools initialIsOpen={true} />
    <App />
    </QueryClientProvider>
  
);

위와 같이 사용하면 된다. QueryClientProvider의 사용법은 기존과 같지만 ReactQueryDevtools는 <App />를 감싸는 형태가 아니라 독립적으로 위에 선언만 해주면 되더라. 기존 방식대로 아래와 같이 적용했었는데 적용이 안돼서 공식문서를 찾아보고 해결했다.

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

2. useQuery

useQuery 또한 사용 방법이 조금 달라졌는데, 기존 방법 부터 알아보자.

기존 방법

const fetchtempData = async () => {
    const res = await axios.get('https://62debc799c47ff309e7aeb36.mockapi.io/api/tempuser');
    
    return res.data;
  }

const queryfetch = useQuery('temp_query', fetchtempData, {
    onSuccess: (data)=> {
      console.log(data)
    },
    staleTime:10000
  })

위와 같이 useQuery의 query key 값을 단순히 문자열로 선언해도 됐었는데 이제는 안되는 것을 알 수 있었다. 그리고 공식문서에서도 key 값이 하나 일지라도 배열 안에 key값을 넣어서 사용하라고 나와있었다.

이제는 아래와 같이 사용해야한다.

새로운 방법

const fetchtempData = async () => {
    const res = await axios.get('https://62debc799c47ff309e7aeb36.mockapi.io/api/tempuser');
    
    return res.data;
  }

const queryfetch = useQuery(['temp_query'], fetchtempData, {
    onSuccess: (data)=> {
      console.log(data)
    },
    staleTime:10000
  })

useQuery의 query key 값을 배열로 넘겨주었음을 알 수 있다.

3. useMutation

useMutation의 경우 이전과 비교했을 때 딱히 달라진 점은 찾지 못했다. 하지만 쿼리 무효화의 방식이 조금 달라진 것 같았다.(invalidateQueries) 이것에 대해서 조금 적어보겠다.

invalidateQueries

쿼리 무효화란, 간략하게 설명하면 useQuery()로 서버에 저장되어 있는 데이터를 받아와 사용하는데 그 데이터가 변경되었을 경우 즉, stale한 상태, 상한 상태가 되었을 경우 useQuery로 받아오는 데이터가 리패치 되어 새로운, fresh한, 신선한 데이터를 자동으로 받아오게 하기 위해서 사용되고, 나도 그 목적으로 사용해봤다.

기존 방식의 사용 코드

import logo from './logo.svg';
import './App.css';
import axios from 'axios';
import { QueryClient, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import React from 'react';

function App() {
  const [tempdata, settempdata] = React.useState('');
  const nicknameRef = React.useRef('');
  const queryClient = new QueryClient(); // QueryClient는 provider 정의 할 때만 사용한다.
  
  const fetchtempData = async () => {
    const res = await axios.get('https://62debc799c47ff309e7aeb36.mockapi.io/api/tempuser');
    
    return res.data;
  }

  const addData = (data) => {
    return axios.post("https://62debc799c47ff309e7aeb36.mockapi.io/api/tempuser", data);
  }

  const queryfetch = useQuery(['temp_query'], fetchtempData, {
    onSuccess: (data)=> {
      console.log(data)
    },
    staleTime:10000
  })

  const {mutate} = useMutation(addData, {
    onSuccess: ()=> {
      // 데이터 목록을 다시 불러오면 됨\
      nicknameRef.current.value = '';
      
      queryClient.invalidateQueries('temp_query');
    }
  });
  

  const clickHandler = () => {
    const data = {nickname:nicknameRef.current.value}
    mutate(data);
  }
  
  console.log(queryfetch.data);
  if(queryfetch.isLoading) {
    return <p>no data</p>
  }

  return (
    <div className="App">
      {queryfetch.data.map((item, index) => <p key={index}>{item.nickname}</p>)}
      <input ref={nicknameRef}></input>
      <button onClick={clickHandler}>추가하기</button>
    </div>
  );
}

export default App;

서버에 저장된 데이터를 useQuery로 받아와 jsx에서 array.map으로 모든 데이터를 보여주고 있고, input 태그에 값을 입력하여 버튼을 누르면 서버에 데이터가 추가되는 간단한 로직이다.

하지만 위와 같이 사용하면 서버에 저장된 데이터가 바뀌어서 데이터가 상해도 useQuery로 새로운 데이터를 받아오지 못했다.

const queryClient = new QueryClient();
//...생략
const {mutate} = useMutation(addData, {
    onSuccess: ()=> {
      // 데이터 목록을 다시 불러오면 됨\
      nicknameRef.current.value = '';
      
      queryClient.invalidateQueries('temp_query');
    }
  });
  

  const clickHandler = () => {
    const data = {nickname:nicknameRef.current.value}
    mutate(data);
  }

위 처럼 QueryClient 객체를 새로 생성하고 그 객체 안의 invalidateQueries 메서드를 사용하여 쿼리를 무효화 하였기 때문이었다. 기존 방식에서는 이 방식으로 쿼리 무효화가 가능했지만 지금은 안 되는 것 같다.

새로운 방식 - useQueryClient()

const queryClient = useQueryClient();
//...생략
const {mutate} = useMutation(addData, {
    onSuccess: ()=> {
      // 데이터 목록을 다시 불러오면 됨\
      nicknameRef.current.value = '';
      
      queryClient.invalidateQueries('temp_query');
    }
  });
  

  const clickHandler = () => {
    const data = {nickname:nicknameRef.current.value}
    mutate(data);
  }

QueryClient 객체를 선언하여 사용하는 것 대신에 useQueryClient라는 훅으로 쿼리 무효화를 사용할 수 있다. 스택오버플로우를 참고하여 해결하였다.

https://stackoverflow.com/questions/68577988/invalidate-queries-doesnt-work-react-query

📌 전체 참고 : https://tanstack.com/query/v4

profile
유능한 프론트엔드 개발자가 되고픈 사람😀

0개의 댓글