상태 관리 라이브러리 - Recoil (4. 비동기 처리)

eeensu·2023년 8월 5일
0
post-thumbnail

recoil에서는 비동기적인 API호출도 가능하다. recoil은 데이터 플로우 그래프를 통해 상태를 매핑하는 방법과 파생된 상태를 react component에 제공한다.
이러한 플로우에 속한 함수들은 물론 비동기가 될 수도 있다. 이는 비동기 함수들을 동기 react 컴포넌트에서 사용하게 쉽게 만들어준다.




기존의 selector의 get 함수를 async로 적용하면 비동기 로직을 처리할 수 있다. 다음은 지정된 api를 통해 id가 1인 유저의 이름을 비동기로 받아오는 selector 예제이다.
const currentUserNameQuery = selector({
  key: 'currentUserNameQuery',
  get: async ({ get }) => {
    const response = await axios.get('/api/username?id=1');
    return response.name;
  },
});


하지만, react의 렌더 함수가 동기인데 promise가 resolve 되기 전에 무엇을 렌더 할 수 있을까? recoil은 보류중인 데이터를 다루기 위해 React Suspense와 함께 동작하도록 디자인되어 있다. 컴포넌트를 Suspense의 경계로 감싸는 것으로 아직 보류중인 하위 항목들을 잡아내고 대체하기 위한 UI를 렌더하게 해준다.

<React.Suspense fallback={<div>Loading...</div>}>
  	<CurrentUserInfo />			{/* 비동기 selector를 이용하는 컴포넌트를 Suspense 안에 넣어준다. */}
</React.Suspense>




selectorFamily

하지만 대부분의 비동기로 호출하는 API는 호출할 데이터의 특정 인자를 쿼리로 호출한다.
recoil은 인자를 받아 selector를 호출할 수 있도록 하는 selectorFamily를 제공한다. 아래와 같이 사용할 수 있다.

  1. store.ts에서 selectorFamily 작성
export const currentUserQuery = selectorFamily({
    key: 'currentUserQuery',
  
  	// 인자를 받아올 수 있도록 중첩 함수를 사용
    get: (id: string) => async () => {
      	
      	// axios를 통해 비동기 api 호출
        const res = await axios.get(`/api/username?id=${id}`);
        
        return res.data.username;
    }
});

<br>


  1. msw 헨들러를 다음과 같이 작성 (모의 데이터)
// 더미 데이터
const tableOfUsers: User[] = [
    {
        username: 'Grag'
    },
    {
        username: 'Alex'
    },
  	{
      	username: 'Milick'
    }
];


export const handler = [
    rest.get('/api/username', async (req, res, ctx) => {
        const index = Number(req.url.searchParams.get('id'));	// 쿼리에 있는 id 변수를 받아옴

        return res(
            ctx.json({         
              	// 받아온 쿼리는 1이고, 배열의 1번째에는 Alex가 있음
                username: tableOfUsers[Number(index)]	
            })
        );
    }),
];

3. 컴포넌트에서 작성한 selectorFamily를 호출
const SynchronousExample: FC = () => {

    const { username } = useRecoilValue<User>(currentUserQuery('1'));	// 인자로 전달

    return (
        <div>               
        	// 비동기 api가 로딩중일 때는 fallback의 element가 렌더된다.
            <React.Suspense fallback={<div>Loading...</div>}>
                user : {username}
            </React.Suspense>
        </div>        
    );
};


  1. 에러 바운더리 작성
    api를 호출하면 여러가지의 이유들로 인해 error를 리턴할 수 있다. 이러한 상황에 맞춰 사용자의 UI화면에 보여줄 에러 바운더리를 작성한다.


동기 로직을 처리하는데 있어서 selectorFamily의 이점은 코드의 구조를 더 잘 조직화하고 관리하기 쉽게 만들어주며, 효율적인 리소스 사용과 유연한 상태 관리를 가능하게 한다. 이를 활용하면 상태 관리 라이브러리에서도 데이터 패칭을 손쉽게 다룰 수 있다.

profile
안녕하세요! 26살 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글