useAsync とは
useAsync
は、react-use
というReact アプリケーションでよく使われる機能を簡単に実装するための便利なフックライブラリの中のひとつです。
useAsync のドキュメントを読んでみる
useAsync
は、非同期関数(またはプロミスを返す関数)を解決する React フック です。
Reference
useAsync(fn, args?: any[]);
-
fn
: 非同期関数。非同期処理を実行し、結果を返す。 -
args?
: 依存配列。この配列に指定した値が変わると、useAsync
内の非同期関数が再度呼び出される。依存配列が空の場合は、最初のレンダリング時にのみ実行される。
Usage
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
の3つのステートを管理している
へ〜。エラーハンドリングもしやすくて、なんかよさそうな感じがする!!!
refactor: サンプルコードの三項演算子をやめてみる
三項演算子をやめて早期リターンしてしまう書き方もよいのでは?ということで、リファクタリングしつつ、jsx から 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 だけ使えればいいんだけどな・・・
と、思うこともあるかもしれない。
分割代入でいけるのか・・・?
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 のリストが配列で返ってくることを想定して書いてみた。
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
には他にも色々フックが用意されているみたいなので、うまく活用できるといいな〜。