【React.js/Next.js】axios での取得データを戻り値として戻す方法
背景
もともと、 axios
でのデータ取得を下記の方法で実現していました。
- API コールを非同期処理(厳密には「ノンブロッキング」)である axios を用いて行ない、その値の取得を then の中にて useState を用いて保持する
- そして、取得のたびに useEffect で検知し、次の処理を実行するという流れです。
この方法だと、基本的に、APIコールの回数分だけ
- useState の定義
- useEffect の処理記載
が必要となってしまい、コードの一覧性が低くなってしまう問題がありました。
そのため、 axios での取得結果を then の中ではなく、戻り値として受け取り、同期的に扱う方法がないかと模索し始めました。
やりがちな失敗
まず、最初に行なったのが、下記の方法です。
const call = () => {
const result = axios.get(url).then((res) => {
return res;
});
console.log(result);
};
useEffect(() => {
call();
}, []);
axios の then の中で、レスポンスを return する方法です。誰もがまず初めにこちらを試してみると思うのですが、axios は Promise 型を用いているため、うまくいきません。
下記のような Promise のプロパティが取得できるだけです。
結論
結論、下記の記述のうち、allInfo
に関してうまく取得できます。( result
の方は取得できません。 )
export const Child = () => {
const getAnimalInfo = async () => {
return await axios.get('http://localhost:3000/api/animal');
};
const getFoodInfo = async () => {
return await axios.get('http://localhost:3000/api/food');
};
const getAllInfo = async () => {
const animalInfo = await getAnimalInfo();
const foodInfo = await getFoodInfo();
const allInfo = {
animalName: animalInfo.data.animalName,
age: animalInfo.data.age,
foodlName: foodInfo.data.foodName,
foodName: foodInfo.data.taste,
};
console.log('allInfo->', allInfo);
return allInfo;
};
useEffect(() => {
const result = getAllInfo();
console.log('result->', result);
}, []);
return <>Consoleにて確認</>;
};
取得結果
実装ポイント
実装のポイントは、下記の点です。
- axios を呼び出すメソッドA(
getAnimalInfo
とgetFoodInfo
)はasync
とする - axios 実行の際に、
await
を付与し、その結果を return する - メソッドAを呼び出すメソッドB(
getAllInfo
)もasync
とする。 - メソッドAは
await
で呼び出す
こうすることによって、axios での取得結果を戻り値として扱うことができます。
※プロジェクトは下記よりご覧ください。
わざわざ非同期メソッドである axios を同期メソッド的に使ってよいの?
結論、よいと考えています。
実際の意図は不明ですが、axios
は node.js
で動くパッケージであり、 node.js
はノンブロッキング(※)が前提となる実行環境のため、 axios
はノンブロッキング処理が行われているだけだと考えるからです。
※ノンブロッキング処理は非同期処理とは異なり、処理完了の通知がくる処理のことを言います。(詳しくは「参考」記載の記事をご覧ください。)
node.js は多数のアクセスに対応するために、シングルプロセス・シングルスレッドで処理を行うため、ノンブロッキング処理を重要視しますが、SPAの場合、ブラウザで処理を行うため、ノンブロッキング処理がそこまで重要視されるとは考えにくいです。
そのため、無理してノンブロッキング処理を行う必要はなく、同期処理としてもよく、 axios
を同期メソッド的に使用してもよいと考えております。
Discussion