[React Query] react-query로 로딩 화면 나타내기

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

웹 어플리케이션을 구현할 때 로딩 화면을 많이 구현한다.
로딩 화면은 좋은 사용자 경험을 제공하기 위해 필수적으로 구현이 되어야 한다고 생각한다. 서버에서 데이터를 받아오는 동안 화면이 아무것도 보여주지 않는다면 사용자는 어플리케이션이 실행되고 있는건지 아닌건지 판단하기가 어렵기 때문이다.

Redux

여태 나는 redux-thunk로 비동기 API 통신을 많이 다뤘었는데, 이때는 로딩 상태를 판단하는 isLoading 값을 위한 Slice를 따로 만들어 thunk 함수가 실행 될 때마다 isLoading 값을 변경하는 방법으로 로딩 화면을 나타내곤 했다. 아래는 내가 실제로 작성했던 코드이다.

  • loadingSlice.js
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
    isLoading:false
}

const loadingSlice = createSlice({
    name:'loading',
    initialState,
    reducers: {
        setTrueLoading:(state) => {
            state.isLoading = true;
        },
        setFalseLoading:(state) => {
            state.isLoading = false;
        }
    }
})

const loadingActions = loadingSlice.actions;
export { loadingActions };
export default loadingSlice.reducer;
  • postingSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import instance from "../../shared/axios";
import { loadingActions } from "./loadingReducer";

const initialState = {
    postings:[]
}



export const fetchPostingsFirst = createAsyncThunk('posting/fetchPostingFirst', async (information, { dispatch }) => {
    const { target } = information;
    let res;
    dispatch(loadingActions.setTrueLoading());
    dispatch(postingActions.setDefaultPosting());

    if(target === 'main') {
        res = await instance.get('/api/posts').catch((e) => console.log(e));
    }
    else if(target === 'mypage') {
        res = await instance.get('/api/post/myposts').catch((e) => console.log(e));
    }

    else if(target === 'bookmark') {
        res = await instance.get('/api/bookmark/').catch((e) => console.log(e));
    }
    const data = res.data;
    console.log(data);
    dispatch(loadingActions.setFalseLoading());

    return data;
    
})

postingSlice.js에서 loadingSlice.js의 isLoading값을 thunk 실행 할 때마다 적절하게 변경해주고 있는 것을 알 수 있다.

이와 비슷하게 isLoading 값을 컴포넌트 단에서 관리를 한다면, useState를 사용하여 state로 관리할 수도 있다.

하지만 react-query에서는 더 간단하게 React의 suspense를 사용하여 해결할 수 있다.

React-Query

suspense 미사용

import axios from 'axios';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import React from 'react';

function App() {
  const [tempdata, settempdata] = React.useState('');
  const nicknameRef = React.useRef('');
  const queryClient = useQueryClient(); // QueryClient는 provider 정의 할 때만 사용한다.
  
  const fetchtempData = async () => {
    const res = await axios.get('https://62debc799c47ff309e7aeb36.mockapi.io/api/tempuser');
    
    return res.data;
  }
  // react query에는 isLoading 값이 이미 존재함.
  // 따로 isLoading을 만들어서 관리할 필요가 없음.
   if(queryfetch.isLoading) {
    return <p>no data</p>
   }


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

React suspense를 사용하지 않는 방법이다. react-query에서는 isLoading 값을 내장시켜 지원한다.
따라서 redux에서 했던 것 처럼 isLoading을 따로 만들어 관리할 필요가 없다.

하지만 단점이 있다. 어플리케이션 규모가 커지고 컴포넌트도 많아진다면, react-query에서도 isLoading을 하나하나 다 작성하고 관리해야한다.

API요청을 보낼 때 마다 isLoading을 체크해야한다.

isLoading 뿐만 아니라 status라는 값으로도 로딩 중인지 아닌지 판별할 수 있다. 궁금한 사람은 나중에 찾아보기

suspense 사용

1. suspense가 뭐야?

서스펜스는 React v16.6에 실험적인 기능으로 추가가 되었고 React v18에 정식 기능이 되어 추가가 되었다. 어플리케이션의 성능을 향상시키기 위해 코드스플리팅을 해야하는 상황에서 동적으로 import 된 컴포넌트들을 suspense를 이용하여 렌더링, 처리해야한다.

React v18에 정식 기능이 되고 난 후, suspense는 단지 코드스플리팅에 사용될 뿐만 아니라, 로딩 화면을 분기처리하여 보여줄 수 있도록 기능이 추가가 되었다.

자세한 사용 방법은 생략하겠다.

2. react-query + react suspense

react-query에서는 react suspense를 쉽게 다룰 수 있고 이를 이용하여 로딩 화면 분기처리를 쉽게 할 수 있다. 어떻게 하는지 코드를 보면서 알아보자.

  • 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({
  defaultOptions: {
    queries: {
      suspense:true
    }
  }
});

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.Suspense fallback={<div>로딩중이에요!!!!</div>}>
  <QueryClientProvider client={queryClient}>
    <ReactQueryDevtools initialIsOpen={true} />
    <App />
    </QueryClientProvider>
    </React.Suspense>
);

suspense로 전체를 감싼다.
error boundary와 비슷하게 fallback이라는 속성에 로딩 중 렌더링 할 컴포넌트를 넣으면 된다.

그리고 queryClient에 defaultOptions를 설정할 수 있는데, react-query의 전역 설정을 할 수 있다.
react-query의 장점으로, suspense 속성을 true로 바꿔주면 suspense 설정이 완료할 수 있어 매우 간단하다.

이렇게 하면 서버와의 통신으로 loading 순간일 때 알아서 로딩 화면을 나타내준다.

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

0개의 댓글