> For the complete documentation index, see [llms.txt](https://shindongri89.gitbook.io/recoil-todo-list/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shindongri89.gitbook.io/recoil-todo-list/1-.-about-recoil/4..md).

# 4. 비동기 데이터 쿼리

Redux 에선 비동기 데이터 쿼리를 위해 redux-thunk, redux-observable, redux-saga 등의 [Middleware](https://redux.js.org/understanding/history-and-design/middleware) 를 사용해야 합니다.

Middleware 는 action 을 dispatch 하고 reducer 에서 상태 업데이트를 하기 전 비동기 처리(예: 네트워크 요청, setTimeout)를 하는 **중간자** 역할이라고 보면 됩니다.

Redux Middleware 는 비동기 처리를 위해 여전히 강력한 도구지만 이를 위해 추가되는 boilerplate 코드가 많아지는 것은 무시할 수 없습니다.

당연히도 앱의 규모가 커질 수록 복잡도가 늘어나고 코드 양이 더욱 방대해집니다.

이와는 다르게 **Recoil 에선 동기 / 비동기 함수 모두 `selector` 에서 처리할 수 있습니다.**

단, React 의 render() 함수가 동기이기 때문에 promise 가 resolve 되기 전에 렌더링 할 수가 없습니다.

이때 대기중인 데이터를 처리하기 위해 Recoil 은 [React Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html) 와 함께 사용되도록 디자인되어있습니다.

아래의 예처럼 컴포넌트를 Suspense 로 감싸서 대기중인 하위 항목들을 잡아내고 fallback UI 를 대신 렌더합니다.

```jsx
// atom.js
export const todoIdState = atom({
  key: "todoIdState",
  default: 1
});

export const todoItemQuery = selector({
  key: "todoItemQuery",
  get: async ({ get }) => {
    const id = get(todoIdState);

    const response = await axios.get(
        `https://jsonplaceholder.typicode.com/todos/${id}`
    );

    return response.data;
  }
});

// App.js
import { RecoilRoot } from "recoil";
import { Suspense } from "react";

import Container from "./container";

export default function App() {
  return (
      <RecoilRoot>
        <Suspense fallback={() => <p>Loading...</p>}>
          <Container />
        </Suspense>
      </RecoilRoot>
  );
}

// container/index.js
import { todoItemQuery } from "../atom";
import { useRecoilValue } from "recoil";

const Container = () => {
  const data = useRecoilValue(todoItemQuery);

  return <div>{data.title}</div>;
};

export default Container;
```

## 파라미터에 따라 비동기 데이터 요청

파라미터를 기반으로 쿼리하고 싶을 땐 [`selectorFamily`](https://recoiljs.org/ko/docs/api-reference/utils/selectorFamily) 를 사용할 수 있습니다.

```jsx
// atom.js
import axios from 'axios';
import { selectorFamily } from 'recoil';

export const todoItemQuery = selectorFamily({
  key: "todoItemQuery",
  get: (id) => async () => {
    const response = await axios.get(
        `https://jsonplaceholder.typicode.com/todos/${id}`
    );

    return response.data;
  }
});


// App.js
import { RecoilRoot } from "recoil";
import { Suspense } from "react";

import Container from "./container";

export default function App() {
  return (
      <RecoilRoot>
        <Suspense fallback={() => <p>Loading...</p>}>
          <Container id={1} />
        </Suspense>
      </RecoilRoot>
  );
}


// container/index.js
import { todoItemQuery } from "../atom";
import { useRecoilValue } from "recoil";

const Container = ({ id }) => {
  const data = useRecoilValue(todoItemQuery(id));

  return <div>{data.title}</div>;
};

export default Container;

```
