요즘 핫한🔥 React-Query
라는 라이브러리가 있다. 리액트는 본인들이 라이브러리라고 칭하고 있는데... 라이브러리이기 때문에 갖는 단점들이 몇가지 있다. 뷰 이외의 기능들은 직접 구현하거나 써드파티 라이브러리를 사용해야 한다는 점이다. 즉 자유분방하다는 것!
따라서 data-fetching에 관해서도 규칙이 없었다
흔히들 Redux
와 saga
를 많이 사용하지만 이 또한 정해진 규칙이 없어서 전부 제 각각의 방식으로 데이터를 fetching하고 저장했었다. 또 Redux
의 최대 단점은 보일러플레이트 코드가 너무 많다는 것이다. 맨날 리듀서, 액션, 스토어 돌아다니면서 코드를 수정했는데..물론 duck-pattern을 사용할 수도 있지만 모듈자체가 길어질 수 있으므로 pass 😥
하지만 이제는
React-Query
를 이용하면 이런 문제점들을 어느 정도 해결해줄거 같다.
React-Query에서 중요한 개념인 Client State
와 Server State
에 대해서 알아보자.
React-Query
는 Server State만 관리한다. 리덕스에 익숙하다면 서버 데이터를 받아와서 클라이언트에서 관리해야하는 무언가가 있어야하는거 아닌가? 생각이 들겠지만 그런경우는 극히 드물다!
클라이언트에서 서버 데이터의 캐시를 관리합니다.
loading, error state를 관리합니다.
pagination, infinite scroll도 쉽게 처리할 수 있도록 지원합니다.
prefetching을 쉽게 처리할 수 있도록 지원합니다.
error가 발생할 경우 자동으로 재시도합니다.
request가 성공하거나 실패했을 때 각각 callback을 정의할 수 있습니다.
어찌보면 1번이 React-Query
를 이용하는 가장 큰 이유라고 볼 수도 있겠다. 서버와 프론트의 중간쯤에서 마치 캐시서버같은 역할을 수행해준다.
이제 실제 튜토리얼을 진행하면서 자세하게 사용법을 알아보자.
코드에볼루션 리액트 쿼리를 참고했다.
먼저 CRA를 사용할 것이고 패키지 매니저로는 yarn
을 사용할 것이다.
npx create-react-app react-query-start
cd react-query-start
yarn init -y
다음으로 data-fetching을 해야하니 서버가 필요한데 JSON-Server
를 이용할 것이다.
yarn add json-server
JSON-Server
를 설치하고 root에 db.json
파일을 생성하자.
{
"superheroes": [
{ "id": 1, "name": "Batman", "alterEgo": "Bruce Wayne" },
{ "id": 2, "name": "Spiderman", "alterEgo": "Peter Parker" },
{ "id": 3, "name": "Ironman", "alterEgo": "Tony Stark" }
]
}
그리고 package.json
에 다음 스크립트를 추가해보자.
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"serve-json": "json-server --watch db.json --port 4000"
},
yarn serve-json
을 입력하고 포트 4000번에서 확인하면 다음 데이터가 존재하는 것을 확인할 수 있다.
서버까지 세팅이 완료되었고, 몇 가지 라우팅을 추가해보자.
yarn add react-router-dom
이제 컴포넌트를 세 가지 추가해보자.
/src/components/
밑에 Home.page.js
, SuperHeroes.page.js
, RQSuperHeroes.page.js
를 만든다.
특별한 내용은 없고 세 컴포넌트 모두 다음과 같이 구성한다.
import React from 'react';
function Homepage() {
return <div>Homepage</div>;
}
export default Homepage;
이제 마지막으로 App.js
에 라우팅을 추가해보자.
function App() {
return (
<BrowserRouter>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/super-heroes">Traditional Super Heroes</Link>
</li>
<li>
<Link to="/rq-super-heroes">RQ Super Heroes</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/super-heroes" element={<SuperHeroes />} />
<Route path="/rq-super-heroes" element={<RQSuperHeroes />} />
<Route path="/" element={<Homepage />} />
</Routes>
</div>
</BrowserRouter>
);
}
간단한 스타일도 적용해보자.
App.css
nav ul {
display: flex;
background-color: blanchedalmond;
margin-block-start: 0;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
nav ul li {
list-style-type: none;
margin-right: 16px;
}
import axios from 'axios';
import React, { useEffect, useState } from 'react';
function SuperHeroesPage() {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
axios.get('http://localhost:4000/superheroes').then((res) => {
setData(res.data);
setIsLoading(false);
});
}, []);
if (isLoading) {
return <h2>Loading...</h2>;
}
return (
<>
<h2>Super Heroes Page</h2>
{data.map((hero) => {
return <div key={hero.name}>{hero.name}</div>;
})}
</>
);
}
export default SuperHeroesPage;
컴포넌트들이 마운트되면 useEffect
가 실행되면서 superheroes
엔드포인트로 요청을 보내고 데이터를 받아서 state로 저장하고 화면에 렌더링해서 보여주는 전통적인 방식으로 구현해보았다.
다음 챕터에서는 React-Query
를 이용해서 좀 더 간단한 방식으로 구현해보자.