Recoil selector를 사용한 비동기 처리

Kyle·2021년 6월 4일
10

React

목록 보기
1/3
post-thumbnail
post-custom-banner

Recoil selector를 사용한 비동기 처리

이번 에어비엔비 프로젝트를 진행하면서 React의 상태관리 라이브러리인 Recoil을 활용했다.

Recoil을 활용하면 context처럼 provider를 사용하지 않아도 전역에서 상태를 관리할 수 있다. 간단한 문법으로 전역에서 관리할 수 있다는 장점이있다.

또한 태생이 리액트이기 때문에 동시성 모드 같이 리액트와의 호환이 좋아서 사용할 때 편리했다.

이제 본론인 selector를 활용해 비동기 처리 하는 방법을 알아보자.


codeSandbox 예제

github의 repository의 star개수를 가져오는 간단한 프로그램으로 이해해보자!

codeSandbox에 간단한 예제로 진행했으며 아래 링크와 결과가 있다.

코드 샌드박스 결과


selector에서 기본 get 요청

selector에서 기본적인 비동기 요청은 매우 간단하다.

아래의 코드의 atomselector는 아래와 같다.

  • githubInfoState: input으로 부터 Github User와 Repository정보를 받아서 저장하는 상태이다.
  • getStars: githubInfoState로부터 Github User와 Repository정보를 get 해와서 Github에 get요청을 한뒤에 star 개수를 반환해주는 selector.

아래의 코드처럼 단순히 get함수에 async함수를 넣어서 사용하는 컴포넌트에서 useRecoilValue해서 값을 가져오면된다.

아래의 코드는 githubInfoState의 상태를 가져와서 사용하기 때문에 githubInfoState상태가 변경 될 때마다 다시 Get 요청을 해서 새로운 값을 가져온다.

  • recoil 상태
export const githubInfoState = atom({
  key: "githubInfomation",
  default: { users: "", repo: "" }
});

export const getStars = selector({
  key: "get/github-repo-stars",
  get: async ({ get }) => {
    const { users, repo } = get(githubInfoState);
    if (!users || !repo) return;
    const url = `https://api.github.com/repos/${users}/${repo}`;
    try {
      const response = await fetch(url);
      const data = await response.json();
      return data?.stargazers_count;
    } catch (err) {
      throw Error("잘못된 깃허브 정보입니다!");
    }
  }
});
  • getStars 를 사용하는 컴포넌트
const Stars = () => {
  const userRepoStars = useRecoilValue(getStars);

  const stars = userRepoStars ? `${userRepoStars}` : "";
  return <StyledStars>{stars}</StyledStars>;
};

이제 위와 같이 작성하면 제출하기를 클릭해서 githubInfoState의 상태가 변경됨에 따라서 자동으로 Stars 컴포넌트의 값이 변경된다.

Suspense

위의 결과를 잘보면 값이 나오기전 loading... 이라는 표시가 보일 것이다. 리액트에서 개발한 라이브러리여서 리액트와 연동이 잘돼있다. 리액트의 Concurrent ModeSuspense를 사용할 수 있다.

Suspense 라는 것은 간단히 설명하면 하위 컴포넌트의 비동기 작업이 완료되지 않았을 때 Suspense의 fallback에 있는 스트링 혹은 컴포넌트 등을 대신 렌더링하는 것이다. 비동기 작업이 완료되면 원래 렌더링해야 되는 컴포넌트가 렌더링 된다.

위의 샌드박스코드에서 아래와 같이 Suspense를 적용했기 때문에 loading이라는 표시를 확인할 수 있다.

const App = () => {
    ...
    return (
        ...
        <Suspense fallback={<div className="stars">loading...</div>}>
            <Stars className="stars" />
        </Suspense>
        ...
    )
}

recoil의 selectorget함수async함수 일 때 Suspense를 필수적으로 작성하게 한다. 그렇기 때문에 로딩처리를 생각하지않고 Suspense에서 간단하게 할 수 있다.


또 다른 Recoil selector에서 비동기 처리를 할 때의 장점

Recoil의 selector를 활용해서 비동기처리를 했을 때 엄청난 장점이 있다. 바로 값을 캐시해 놓는다는 것이다.

어떻게??

selecto의 key값과 get해서 사용하는 atom의 state값을 비교해서 이전에 같은 데이터로 fetch한 것이 있다면 cache에서 바로 처리한다. 아래의 사진을 보면 이해된다.

  • 3번의 요청을 보낸 상태

  • 첫번째 get 요청

  • 2번째 get 요청 from disk cache 라는 글이 보인다.


마무리

간단하게 selector로 비동기처리하는 과정을 알아보았다. 자세한 코드는 위의 codesandbox에서 코드를 보면 쉽게 이해될 것이다.

selector뿐만 아니라 인자를 받을 수 있는 selectorFamily같은 메소드도 있다.

타입스크립트를 사용하면서 selectorFamily의 인자의 타입 때문에 문제가 발생했었는데 이 문제는 다음에 포스팅할 예정이다.

recoil을 사용해서 편하게 비동기처리와 로딩, 에러 처리를 해보자!

profile
Kyle 발전기
post-custom-banner

0개의 댓글