본문 바로가기
React

[React-Query 사용하기]

by 리슨업 2024. 1. 30.

 

#React- Query

React-Query는 데이터 가져오기, 캐싱, 동기화 등 서버상태를 관리할 수 있게 해주며,

 

다른 컴포넌트 끼리도 key를 이용하여 선언한다면 이는 결은 다르지만 redux같이 상태공유 같이

캐싱된 데이터를 공유할 수 있도록 하여  불필요한 요청을 줄이고 어플리케이션의 성능 향상시키는

강력한 라이브러리이다. 

 

 

 

#React-Query 사용하는 이유 '예시'

예로 SPA 형식의 웹페이지에서 게시판을 만든다고 가정한다면 CRUD 기능 이후 데이터 무결성을 위해서 

CRUD 기능 이후 서버에 해당 로직에 필요한 데이터를 재 요청하여 상태업데이트를 해야한다. 

 

AS-IS 방식

const [ board , setBoard ] = useState({
    board : '게시판 이름',
    boardContents : [...],
    board_cnt : null
})

 

보통 위 같은 State를 가진 board라면 'board_cnt' 값을 가지고 페이징을 하고 boardContents의 배열 객채를 map()을 이용해서 게시판 데이터를 구성할 것 이다. 

 

그럼 Create 나 delete 할 경우에 데이터는 데이터베이스와 클라이언트의 데이터의 무결성을 지키기 위해 신규 데이터를 리턴 받아서 사용자에게 직관적으로 보여줄 필요가 있다.

 

그렇다면 상태 업데이트를 해줘야 하는 로직이 필요하다

 

const createBoard = async(data) => { .... } // Create Fetch 로직


const onSubmitHandler = async(e) =>{
	//... 폼데이터 처리 전달
    try{
    	const refrashData = await createBoard('form 데이터 전달');
        
        //상태 업데이트
       setBoard(prev => ({...prev , 
            boardContents : refrashData.contents , 
            board_cnt : refrashData.cnt 
        }))
        
    } 
    catch(error){
    	//에러처리 !
    }
    
}

 

setBoard를 처리해서 상태를 업데이트 시켜 재 랜더링을 유도 시켜야 클라이언트에서도 서버와 동일한 데이터를 보여줄 수 있는데 이 로직을 'react-query'를 이용하면 상태 훅을 선언하고 업데이트 해줘야 하는 로직을 만들 필요가 없어진다.

 

react-query에서 서버 데이터 상태를 자체적으로 관리 할 수있기 때문이다.

 

 

 


 

 

 

#React-Query 설치 및 세팅

 

역시나 패키지로 설치부터 해야한다. 

"리액트는 라이브러리를 반 강제적으로 사용해야 편한 DX가 가능하다란 점 기억하기"

npm install react-query

 

 

react-Query는 트리형태 데이터를 공급하기위해 provider를 선언해야한다.

react-query의 메서드인 "QueryClientProvider" , "QueryClient"를  최 상위 컴포넌트에 선언한다.

 

일반적으로 최상단에서 한번 선언한다.

import { QueryClient , QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();

root.render(
    <QueryClientProvider client={queryClient} > // provider 와 queryClient 선언
        <React.StrictMode>
            <App /> 
        </React.StrictMode>
    </QueryClientProvider>
  
);

 

"QueryClient"는 react-query의 핵심기능을 가지고있는 인스턴스로 서버 상호작용에 의한 서버 상태 등을 관리, 캐싱, 데이터 동기화 등을 수행하여 이를 자식 컴포넌트 들에게 전달하기위해 "QueryClientProvider"를 사용하여 react Query의 기능을 하위 컴포넌트들이 사용 할 수 있도록 해주는 공급한다.

 

 

 

 

#useQuery , useMuation 

const { data , isLoading , error }= useQuery('id' , fetchData);

 

"useQuery"는 첫번째 매개변수를 식별자로 key , 'id' 를 사용하며, 두번째로는 비동기함수를 주로 fetch나 서버로 통신하는 함수를 많이 사용한다. useQuery는 비동기 함수로 패칭된 데이터를 캐싱하고 data, isLoading ,error 등의 객체를 반환한다 

 

 

data : 비동기 함수가 서버요청에서 리턴 받은 데이터를 담은 프로퍼티 

isLoading : 현재 데이터요청, 종료 상태를 boolean값으로 나타낸다.

error : 에러

 

 

 

"useMutation"은 데이터변경 CRUD을 작업처리를 위해 사용된다.

A컴포넌트와 B컴포넌트로 나뉜 컴포넌트라도 상위 컴포넌트에 QueryClientprovider로 트리구조로 구성해두었기 때문에 상태를 useQueryClient 훅으로 손쉽게 데이터를 동기화하여 useState의 set등을 하지 않아도 공유가 가능하다. 

//A 컴포넌트
const { data , isLoading , error } = useQuery('id', fetchData );


//B 컴포넌트
const queryClient = useQueryClient();

const { mutate , isLoading ,isSuccess , data } = useMutation(data => requestFetch(data), {
	onSucess : (data)=>{
    		queryClient.invalidateQueries('id');
        alert('성공!');
    },
    onError : (error)=>{
    	//에러처리
        alert(error.message);
    }
})

 

A,B 컴포넌트는 서로 다른 컴포넌트여도 invalidateQueries를 'id' 키를 가진 useQuery에 데이터를 동기화 시킨다.

뮤테이션이 성공하면 윗 로직의 패치가 성공 된 이후 세번째 매개변수 옵션(onSuccess, onError)을 이용하여 완료,에러 추가 로직을 구성 할 수 있으며 또  isSuccess 프로퍼티를 이용하여도 추가 처리를 해도 된다.

 

useMutation의 반환객체인 "mutate"는 비동기함수를 실행하도록 하는 프로퍼티이며, "data"는 완료 후의 데이터 즉, useQuery에 캐싱한 후 동기화 된 데이터를 참조하고 있는 프로퍼티이다. 

 

AS-IS방식으로는 매번 상태에 set하고 다시 랜더링 시키고 불필요한 패치를 할 경우가 있지만 이 라이브러리를 이용하여 매우 간편하게 서버데이터 동기화가 가능하다

 

 

 

24/3/1추가

"Mutate , MutateAynsc"

Mutate, MutateAynsc 둘다 useMutation의 실행 조작을 담당하는 프로퍼티로 둘 다 비동기적으로 실행된다.

다만 MutateAynsc는 프로미스를 반환함으로 외부에서 추가 로직이 수행가능하며 mutate는 프로미스를 반환하지 않기에 특정 fetch를 실행할때 사용한다. 

 

둘 다 콜백함수로 onSuccess , onError로 후속 조치가 가능하다.

 

mutateAynsc는 다른 비동기 함수와 더불어 추가 로직을 실행하기에 적합하며, mutate는 fire-and-forget방식으로 처리 할때 유용하다. 

 

 


 

 

#useQuery를 이용한 페이징 처리

예로 게시판에 10개씩 나누어 페이징 처리된 게시판이 있다고 가정하고 페이징 할때마다 쿼리스트링을 이용해서 10개씩 데이터를 반환 받아야한다. 

 

이때 useQuery의 의존성( Dependeny ) 을 이용하여 간단하게 처리 가능하다. 

 

우선 page를 가져오고..

const url = new URL(window.location);
const page = url.searchParams.get('page') || 1;

 

 

page를 ['id',page]로 반영한다. 이때 id는 key와 동일하고, page는 의존성으로 구별된다.

const url = new URL(window.location);
const page = url.searchParams.get('page') || 1;

const { data } = useQuery(['id', page], (data)=>fetchData(data))

 

page가 변경되면 fetchData는 재 실행이 되며 별도의 로직이 필요없이도 10개씩 나누어진 데이터를 반환 받을 수 있다.