Skip to main content

Command Palette

Search for a command to run...

[ 살펴보기 ] Recoil - Asynchronous Data Query

Updated
2 min readView as Markdown
[ 살펴보기 ] Recoil - Asynchronous Data Query
C

A developer living in Busan, Korea

Selector를 통해서 데이터를 반환하기 위해 비동기 처리가 필요할 때는 어떻게 해야할까? 아주 간단하다. selector get 함수내에서 async-await를 통해 필요한 비동기 처리를 해주고 그 값을 반환해주면 된다

import { selector } from "recoil";

export const userListSelector = selector({
  key: "userListSelector",
  get: async () => {
    const result = await apiGetUserList();
    return result;
  },
});

하지만 위처럼 async를 통해 값을 반환한다면 promise가 resolve될 때까지 selector의 상태는 pending이 되므로 위의 selector를 사용하는 component를 Suspense로 처리해주는 과정을 잊지말자

import { useRecoilValue } from "recoil";
import { userListSelector } from "@/states/user";

const UserRecoilComp = () => {
  const userData = useRecoilValue(userListSelector);
  ...
}

만약 UserRecoilComp라는 컴포넌트에서 위에서 선언한 async selector를 사용하고 있다면 다음과 같이 Suspense로 해당 컴포넌트를 감싸서 pending state동안 보일 fallback 화면을 처리해준다

import React, { Suspense } from "react";

<Suspense fallback={<div>Component Loading...</div>}>
  <UserRecoilChildComp />
</Suspense>

Error가 발생했을 땐 어떻게 해야할까

비동기 처리를 할 때 언제나 실행되는 로직이 정상적인 값을 반환할 것이라는 보장은 없다. 그렇다면 selector에서 비동기 처리를 할 때 error 처리는 어떻게 해야할까? 우리가 흔히 하는 error 처리와 크게 다를 것은 없다. 다음의 예제를 살펴보자

export const userListSelector = selector({
  key: "userListSelector",
  get: async () => {
    try {
      const result = await apiGetUserList();
      return result;
    } catch (err) {
      throw new Error(err.message);
    }
  },
});

select에서 비동기 처리를 할 때 만약 apiGetUserList를 처리하는 도중 에러가 발생하면 catch block에서 error를 throw한다

그리고 selector에서 error가 throw되면 해당 selector를 사용하는 component에서도 error가 throw된다. 그렇기에 error가 throw될 수 있는 selector를 사용하는 component에서도 error를 처리할 수 있는 조치가 필요하다.

<ErrorBoundary fallbackRender={UserErrorBoundary}>
  <Suspense fallback={<div>Recoil Loading...</div>}>
    <UserRecoilChildComp />
  </Suspense>
</ErrorBoundary>

위의 예제처럼 추가해 만약 component에서 error가 throw되었을 때 ErrorBoundary를 통해 해당 error를 처리할 수 있도록 조치할 수 있을 것이다.

useRecoilValueLoadable

만약 Suspense와 ErrorBoundary를 프로젝트에서 사용하지 않고 있다면 어떻게 해야할까? 만약 Suspense와 ErrorBoudnary없이 selector에서 비동기 처리를 해야한다면 다음과 같이 할 수 있다

import { useRecoilValueLoadable } from "recoil";

const userData = useRecoilValueLoadable(userListSelector);
  const { state, contents } = userData;
  if (state === "loading") {
    return <div>Loading ...</div>;
  }

  if (state === "hasError") {
    return <div>Error occured!</div>;
  }

...

Recoil의 useRecoilValueLoadable를 사용하면 위의 예제와 같이 state별로 filter해서 상황에 맞게 처리할 수 있다

More from this blog

[ 살펴보기 ] TypeORM - Transactions, Migration

Transation Database 종류에 따라 detail한 부분은 차이점이 조금씩 있겠지만 각 sql statement는 개별적인 transaction block을 통해 실행되며 Database 설정에 따라 sql statement의 실행 결과가 자동으로 commit되어 영구히 적용되거나 commit을 직접 실행하기 전까지는 영구히 적용되지 않을 수 있다. 대부분의 경우 default로 sql statement 실행 결과가 자동으로 comm...

Feb 9, 20256 min read
[ 살펴보기 ] TypeORM - Transactions, Migration

Dev Diary

184 posts