본문 바로가기
Study/React

React ) Recoil 로 Axios 비동기 처리하기

by JongIk 2022. 5. 10.
반응형

React-News Web App 에 Recoil 적용하기

기존에 react hook 방식과 redux-saga 를 적용해 만든 HackerRank News Web App 을 Recoil 을 이용해 상태를 관리하는 방식으로 다시 제작해봤습니다.
HackerRank News OpenAPI 를 활용했습니다.

실행 화면

Code

Recoil 초기 설정

먼저 npm i recoil 을 통해 recoil 을 설치합니다.

Recoil 은 Redux 와 비교하면 초기설정이랄 것도 없습니다.

import { RecoilRoot } from "recoil";
function App() {
  return (
    <>
      <RecoilRoot>
        <React.Suspense fallback={<div>Loading...</div>}>
          <Router>
            <ToolBar />
            <Routes>
              ...
            </Routes>
          </Router>
        </React.Suspense>
      </RecoilRoot>
    </>
  );
}

그냥 RecoillRoot 로 감싸주면 끝입니다. 너무 좋습니다.

atom.js

import { atom } from "recoil";

export const pathNameState = atom({
  key: "pathNameState",
  default: "/",
});

export const askIDState = atom({
  key: "askIDState",
  default: 0,
});

export const userIDState = atom({
  key: "userIDState",
  default: 0,
});

atom.js 에는 상태가 변화함에 따라 api 를 호출하면서 각각 다른 파라미터를 넘겨주어야 할 때 필요한 변수들을 선언했습니다.
pathNameState 는 기존의 NewsList.js, JobsList.js, AskList.js 3가지 파일들을 ListItem.js 로 통합하면서 url 주소에 따라 News, Ask, Jobs 각각의 정보를 표시해주기 위해 선언했습니다.

selector.js

import { selector } from "recoil";
import { fetchAsk, fetchItem, fetchJobs, fetchNews, fetchUser } from "../api";
import { askIDState, pathNameState, userIDState } from "./atoms";

export const getItemList = selector({
  key: "getItemList",
  get: async ({ get }) => {
    let path = get(pathNameState);
    let response;
    if (path === "/news" || path === "/") {
      response = await fetchNews();
    } else if (path === "/ask") {
      response = await fetchAsk();
      console.log(response.data);
    } else if (path === "/jobs") {
      response = await fetchJobs();
    }
    return response.data;
  },
});

export const getAskInfo = selector({
  key: "getAskInfo",
  get: async ({ get }) => {
    let askId = get(askIDState);
    let response = await fetchItem(askId);
    return response.data;
  },
});

export const getUserInfo = selector({
  key: "getUserInfo",
  get: async ({ get }) => {
    let userId = get(userIDState);
    let response = await fetchUser(userId);
    return response.data;
  },
});

selector 함수는 atom.js 에서 선언한 변수의 상태가 변화하는 것을 감지할 수 있습니다.
유저 상세페이지, 질문글 상세페이지 등 호출할때마다 다른 ID값을 넘겨주어야 하는 경우에는 위 코드처럼 atom.js 에서 선언한 ID 값들을 구독(?) 하면 됩니다.

ListItem.js

import React, { useEffect } from "react";
import { Link, useLocation } from "react-router-dom";
import { useRecoilState, useRecoilValue } from "recoil";
import { pathNameState } from "../../state/atoms";
import { getItemList } from "../../state/selector";

export function ListItem() {
  const { pathname } = useLocation();
  const [pathName, setPathName] = useRecoilState(pathNameState);
  const ItemList = useRecoilValue(getItemList);
  useEffect(() => {
    setPathName(pathname);
  });
  return (
    <>...</>
  )
  • 현재 url 의 경로인 pathname 값을 atom.js 에서 선언한 pathNameState 에 넣어줍니다.
  • 그러면 useRecoilValue 로 selector.js 의 getItemList 함수를 호출합니다.
  • 마지막으로 selector.js 의 getItemList 함수에서는 변화한 state 값을 인지해 해당되는 데이터를 요청한 뒤 받아오게 됩니다.

전체 코드 보러가기

3.recoil 브랜치를 통해 코드를 확인하실 수 있습니다.
GitHub

반응형

댓글