useAsync の使い方を学んでみた

# useAsync とは
`useAsync`は、`react-use`というReact アプリケーションでよく使われる機能を簡単に実装するための便利なフックライブラリの中のひとつです。

[GitHub > react-use](https://github.com/streamich/react-use)



# useAsync のドキュメントを読んでみる
[GitHub > react-use > useAsync](https://github.com/streamich/react-use/blob/master/docs/useAsync.md)
<br>

`useAsync` は、非同期関数（またはプロミスを返す関数）を解決する React フック です。

## Reference
```ts
  useAsync(fn, args?: any[]);
```
- `fn`: 非同期関数。非同期処理を実行し、結果を返す。
- `args?`: 依存配列。この配列に指定した値が変わると、`useAsync`内の非同期関数が再度呼び出される。依存配列が空の場合は、最初のレンダリング時にのみ実行される。

## Usage
```jsx
import {useAsync} from 'react-use';

const Demo = ({url}) => {

  // useAsync を使って非同期関数を呼び出す
  const state = useAsync(async () => {
    const response = await fetch(url);   // URL からデータを取得する
    const result = await response.text();   // レスポンスをテキストとして取得する

    return result   // 取得した結果を返す
  }, [url]);   // URL が変わる度に非同期関数が再実行される

  return (
    <div>
      {state.loading
        ? <div>Loading...</div>   // 読込中は「Loading...」を表示する
        : state.error
          ? <div>Error: {state.error.message}</div>   // エラーが発生した場合は、エラーメッセージを表示する
          : <div>Value: {state.value}</div>   // 成功した場合は取得したデータを表示する
      }
    </div>
  );
};
```

- `useAsync` は、非同期関数の戻り値を返す
- `useAsync` の戻り値は、オブジェクト
- `useAsync` は戻り値に対して、`loading`、`error`、`value`の３つのステートを管理している

へ〜。エラーハンドリングもしやすくて、なんかよさそうな感じがする！！！


# refactor: サンプルコードの三項演算子をやめてみる
三項演算子をやめて早期リターンしてしまう書き方もよいのでは？ということで、リファクタリングしつつ、jsx から tsx に書き換えてみる。

```tsx
import { useAsync } from 'react-use';

interface DemoProps {
  url: string;
}

const Demo = ({ url }: DemoProps) => {
  const state = useAsync(async () => {
    const response = await fetch(url);

    return await response.text();
  }, [ url ]);

  if (state.loading) return <div>Loading...</div>
  if (state.error) return <div>Error: { state.error.message }</div>

  return (
    <div>Value: { state.value }</div>
  );
};

export default Demo;
```

うん、なんかスッキリしてきた。

# state.value だけ使えればいいんだけどな・・・
と、思うこともあるかもしれない。
分割代入でいけるのか・・・？

```tsx
import { useAsync } from 'react-use';

interface DemoProps {
  url: string;
}

const Demo = ({ url }: DemoProps) => {
  const { value: state } = useAsync(async () => {
    const response = await fetch(url);
    
    return await response.text();
  }, [ url ]);

  return (
    <div>Value: { state }</div>
  );
};

export default Demo;
```

`value` の値を `state` という名前で取り出すこと（エイリアス）ができた☆
分割代入からのエイリアス。なんかオシャレ♫

# state の値が配列だったらどうなる？
リポジトリから todo のリストが配列で返ってくることを想定して書いてみた。

```tsx
import { useAsync } from 'react-use';
import { TodoListRepository } from "@/repository/todoRepository.ts";

export const Demo = ({ todoRepository }: { todoRepository:TodoListRepository }) => {
  const { value: todoList } = useAsync(async () => {
    return await todoRepository.getList();
  }, [todoRepository]);

  return (
    <>
      {todoList?.map((todo) => (
        <div key={todo.id}>{ todo.id }: {todo.title}</div>
      ))}
    </>
  );
};
```
うん、いいかも。
`useAsync` の `value` の戻り値の型は、`TodoList[] | undefind` みたいな形になっていて `undefind` が入ってくる可能性があるので、オプショナルチェイニング演算子 ( ?. ) を使って回避したり、`todoList[] || []` みたいな形で `todoList` に `undefind` が入ってきたら空の配列を返すようにするなどの工夫が必要かなと思います。

# おわりに
`useAsync`が何者かわからず、もやもやしたまま使っていたので、スッキリしました！！
`react-use`には他にも色々フックが用意されているみたいなので、うまく活用できるといいな〜。