[ 살펴보기 ] Recoil - Asynchronous Data Query
![[ 살펴보기 ] Recoil - Asynchronous Data Query](https://cdn.hashnode.com/res/hashnode/image/upload/v1715784274427/0cf4db7f-7678-4795-a700-cae96691341a.jpeg)
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해서 상황에 맞게 처리할 수 있다
![[ 살펴보기 ] RDB - Relationships](https://cdn.hashnode.com/res/hashnode/image/upload/v1739711556668/48dc9e84-a621-42aa-9c9f-5fc5c436f0ec.jpeg)
![[ 살펴보기 ] MySQL - Data types](https://cdn.hashnode.com/res/hashnode/image/upload/v1739593589113/530f8704-4d27-42c9-a451-bb5c63150b99.jpeg)
![[ 살펴보기 ] TypeORM - Transactions, Migration](https://cdn.hashnode.com/res/hashnode/image/upload/v1739106042581/980b8133-61d4-406a-a026-65be9c28eace.jpeg)
![[ 살펴보기 ] TypeORM - Relations](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666874402/b688bd0b-b6bb-4f43-87d8-c1b46b59f1b7.jpeg)
![[ 살펴보기 ] TypeORM - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666803591/bef5df17-7dc7-4123-ae55-004d5042df39.jpeg)