Webアプリケーションを開発する場合、APIからデータを取得して表示することがよくあります。
過去の記事でJavaScriptで標準で用意されているfechメソッドを使ったAPIの取得を紹介しましたが、fetchメソッドは最近トレンドになっているReactでも使用できます。
通常のJavaScriptとReactとの書き方の違いを知ってもらうため、今回はReactでfectchメソッドを使ってみたいと思います。
また動画もあるので必要な方は以下よりご覧ください。
Reactでfetchメソッドを使ってAPIを取得する
今回使用するAPIは無料で誰でも使用できる「jsonplaceholder」を使います。
ブログ記事やユーザーデータなどのテストデータをたくさん用意してくれているので、まだ使ったことがない方はお気に入りにでも追加しておくことをお勧めします。
https://jsonplaceholder.typicode.com/
Reactではreturnの場所に画面に表示する内容を書くことになっているので、API処理など裏側で処理するものはreturnの外に書くルールになっています。
import React from "react";
const FetchData = () => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((json) => console.log(json))
.catch(() => alert("error"));
return <></>;
};
export default FetchData;
APIからデータを取得しただけですが、fetchメソッドの部分だけ見ると通常のJavaScriptと書き方は同じですね。
ReactやVueなど新しいライブラリがどんどん生まれていますが、結局はJavaScriptの上位互換でしかないのでメソッドの書き方は一緒なんですね。
そう考えると少しは親しみやすく見えるのではないでしょうか?
fetchメソッドを使うのが初めての方は以下の記事で詳しく解説しているので確認してみてください。
fetchメソッドの使い方はReactでも同じであるのですが、取得したデータの扱い方がReactでは少し特殊になります。
// ここを修正
import React, { useState } from "react";
const FetchData = () => {
// ここを追加
const [data, setData] = useState(undefined);
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
// ここを修正
.then((json) => setData(json))
.catch(() => alert("error"));
return <></>;
};
export default FetchData;
Reactではステート変数というものにデータを格納する仕組みになっています。
またステート変数を使うためには「useState」というものが必要で、こちらは事前にインポートしておく必要があります。
またデータが格納されるステート変数に「データを入れる処理」をしてくれるものをステート関数と言います。
さらにuseStateの引数にはステート変数にデータが入る前には何をセットしておくか、いわゆる初期値を指定しておきます。
fetchメソッドでAPIからデータを取得してきた結果をステート関数であるsetData( )の引数に入れることで、ステート変数であるdataの中身が「undefined → APIからデータ」になる仕組みです。
// useStateをインポートしておく
import React, { useState } from "react";
const FetchData = () => {
// ステート変数をdata, ステート関数をsetDataとする
// ステート変数のdataにはundefinedを初期値に指定
const [data, setData] = useState(undefined);
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
// ステート変数のdataに取得結果を格納する
.then((json) => setData(json))
.catch(() => alert("error"));
return <></>;
};
export default FetchData;
上記のコードで実際にステート変数であるdataにAPIの取得結果が格納されるか確認してみましょう。
現状はまだコンソールでログを確認する形で大丈夫です。
import React, { useState } from "react";
const FetchData = () => {
const [data, setData] = useState(undefined);
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((json) => setData(json))
.catch(() => alert("error"));
// ここを追加
console.log(data);
return <></>;
};
export default FetchData;
ブラウザをリロードすると以下のようになるはずです。
データらしきものは表示できていますが、同じようなものが大量に表示されていますね。
こちら無限ループと言って「APIから同じデータを延々と繰り返し取得し続けている」という状態です。
一旦ブラウザを落としておきましょう。
ReactではuseStateでステート変数の中身にデータを格納していくのですが、「何を」「いつまで」といった具合に条件を指定してあげないと延々とステート変数の中身を更新し続ける仕組みになっています。
こちらを解決するためにuseEffectというものがあります。
// useEffectをインポートしておく
import React, { useState, useEffect } from "react";
const FetchData = () => {
const [data, setData] = useState(undefined);
// ここを修正
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((json) => setData(json))
.catch(() => alert("error"));
}, []);
console.log(data);
return <></>;
};
export default FetchData;
まずuseEffectもインポートが必要なのでuseStateと同じくインポートしておきます。
続いてuseEffectは関数になっていて引数を2つ指定します。
・第一引数:実行したい処理
・第二引数:実行したい処理を実行するタイミング
第一引数で指定するものはAPIの取得なので、すでに作ってあるfetchメソッドのコードをそのまま入れるだけです。
第二引数は状況によって書き方は変わるのですが、[ ](空の配列)にすると「リロード時に1回だけ実行」という意味になります。
上記の状態でもう一度ローカルサーバーを立ち上げてコンソールを確認してみましょう。
先ほどのような無限ループにはならず配列が1個だけ取得できていますね。
取得できた配列の中身を見てみます。
オブジェクトが合計100個あるのが分かります、さらにオブジェクト単体の中身を見てみます。
中には4つのプロパティがあり、英語表記ですが正常にデータを取得できていますね。
今回取得したデータは英語表示のブログ記事になっています。
こちらfetchメソッドに指定したURLをそのままブラウザに打ち込んでも同じデータが確認できます。
https://jsonplaceholder.typicode.com/posts
データが取得できてステート変数であるdataに格納されたので、dataの中身を画面に表示してみたいと思います。
import React, { useState, useEffect } from "react";
const FetchData = () => {
const [data, setData] = useState(undefined);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((json) => setData(json))
.catch(() => alert("error"));
}, []);
console.log(data);
// ここを変更
return (
<>
<div>{data[0].title}</div>
</>
);
};
export default FetchData;
コンソールで確認したように1個ずつのデータは「配列の中にオブジェクトが100個ある」状態になっていたので配列とオブジェクトからデータを表示する書き方をするだけです。
冒頭にも説明しましたがReactでは画面に表示する部分のコードはreturnの中で書くルールです。
上記の場合、「0番目のオブジェクトのtitleの値を表示」という意味になっています。
ブラウザをリロードすると画面にtitleの値が表示されました。
ちなみにですが実はまだやることが残っていて、もう一度ブラウザを閉じて立ち上げ直してみてください。
すると今度は画面には何も表示されておらずコンソールが以下のようになっているかと思います。
何やらエラーになってしまったようです。
よくよく見てみると最初のログが「undefined」になっているのですが、こちらどこかで見た覚えがありませんか?
useStateを使ったステート変数dataの初期値に「undefined」を指定していましたね。
つまりdataの中身は初期値のままでAPIから取得したデータは入ってないことが想像できました。
こちら結論から言うと、「APIの取得に時間がかかっていて、その間に画面の表示をしようとした」ことが原因です。
つまりdataにAPIの取得結果が格納されていない間に、<div>{data[0].title}</div>を実行しようとしたことで「{data[0].title}なんて何も入ってません」と言われてしまったわけです。
こちらを回避する方法は何パターンかあるのですが一番簡単なのはreturn部分の画面に表示するコードを以下のようにすることです。
import React, { useState, useEffect } from "react";
const FetchData = () => {
const [data, setData] = useState(undefined);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((json) => setData(json))
.catch(() => alert("error"));
}, []);
console.log(data);
// ここを変更
return (
<>
{data === undefined ? "" : <div>{data[0].title}</div>}
</>
);
};
export default FetchData;
画面の表示部分のコードについて三項演算子で条件文を作りました。
三項演算子が初めての方がいるかもしれませんが「if文」を書いているのと同じですので安心してください。
条件の内容としては、
・ステート変数dataがundefined(初期値のまま)だったら何も表示しない
・ステート変数dataにAPIのデータがあれば表示する
と言う内容です。
初学者の方にはなかなかイメージしづらいかもしれませんが、APIの取得は僅かながら時間がかかる処理です。
そのような時間がかかる処理を使うときは今回のような条件式で「データがないときにどうするか?」を考える必要があるんです。
エラーではなくローディング画面などにする方が何かと便利だからですね。
以上のような形でReactでfetchメソッドを使ったAPI取得をやってみました。
fetchメソッド単体は全く持って同じ書き方ですが、画面の表示やデータの管理などが通常のJavaScriptと違う部分だったかと思います。
これを機にReactを本腰入れて勉強してみようという方は以下のような本もオススメですので確認してみてください。