今回はReact + Material UIで通信中にスピナーを表示し、通信終了時にメッセージを表示するプログラムを作成します。非同期通信にはaxiosを利用します。
こちらの記事でReact Hook Formを利用してフォームを作成したので、そのプログラムを使います。
-

React Hook Formがいい感じ!
Contentsはじめに使ってみるMaterial UIと使うまとめ はじめに ReactでWebアプリケーションを作る際に自力でフォームを作成するのは、現実的に考えるとやらない方がいいです。自力でフ ...
続きを見る
完成図はこちら↓↓

はじめに
完成したコードはGitHubから取得して下さい。
ソースコードの説明
| src/components/PostContainer.js | スピナーとメッセージの状態管理 |
| src/components/PostForm.js | フォームの描画とそのsubmit処理 |
| src/components/PostLayout.js | 全体のレイアウト |
| src/Utils/SnackBar.js | メッセージのコンポーネント |
| src/Utils/ErrorButton.js | エラーメッセージを確認するためのダミーボタン |
普通にやるとAPI通信は成功するので、エラーハンドリングの確認用にダミーボタンを用意してあります。
APIの通信先
今回はAPIの通信先としてJSONPlaceholderのAPIを使います。ダミーAPIを提供しているサイトです。
このサイトでは様々なリソースがあり、記事やコメント、写真、todoなどを想定したAPIを提供しています。
https://jsonplaceholder.typicode.com/postsにGETメソッドでアクセスすれば記事一覧がJSONで取得できますし、POSTメソッドを送れば201ステータスのレスポンス(+データなど諸々)が帰ってきます。
今回はスピナーとメッセージを表示することが目的であるため、リソースはなんでもいいのですが"/posts"を使用します。
axiosのセットアップ
今回はaxiosで複雑な処理はしませんが、以下のようにinstanceを生成しています。instanceを生成して有効に使う方法は今後紹介予定です。
import axios from "axios";
const instance = axios.create({
baseURL: "https://jsonplaceholder.typicode.com/"
});
export default instance;
使う際は上記のファイルをimportして通常のaxiosと同じように使うだけです。
補足
baseURLを指定しているとアクセスのたびにget("https://jsonplaceholder.typicode.com/posts")とする必要はなく、get("posts")とするだけでよくなります。
スピナーを作成
通信中にスピナーを表示させます。Material UIのBackdropとCircularProgressを使用します。Backdropは画面全体に表示する半透明のパネル(?)的なものです。
まずスピナー+Backdropの状態管理をするために以下のように設定します。
const [progress, setProgress] = useState(false);
デフォルトをfalseにしておき、submitボタンが押されたときにtrueにします。
あとは変数を作り、progressがtrueであればスピナーを、progressがfalseであればフォームを表示する処理を書きます。
/* 通信中であれば、formを非表示にし、スピナーを表示する */
let form = (
<Backdrop className={classes.backdrop} open={progress}>
<CircularProgress color="inherit" />
</Backdrop>
);
if (!progress) {
form = <PostForm setProgress={setProgress} setStatus={setStatus} />;
}
これをreturnメソッド内で{form}のように表示させます。
メッセージを表示
次に通信が成功したのか、失敗したのかを表示する仕組みを作っていきます。
ここではMaterial UIのSnackBarを使います。公式ドキュメントから不要な箇所を削り、色やテキストの部分を変数化しています。
import React from "react";
import Snackbar from "@material-ui/core/Snackbar";
import MuiAlert from "@material-ui/lab/Alert";
function Alert(props) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
const CustomizedSnackbars = props => {
const { open, handleClose, type, message } = props;
return (
<Snackbar open={open} autoHideDuration={3000} onClose={handleClose}>
<Alert onClose={handleClose} severity={type}>
{message}
</Alert>
</Snackbar>
);
};
export default CustomizedSnackbars;
このSnackBarの状態管理は以下のように設定しました。
ポイント
今回はスピナー、メッセージの状態をuseStateを使って管理していますが、プログラムの様々な箇所で使うものですのでReduxのstoreやReactのContextで管理したほうが便利です。
/* SnackBarの状態管理(ReduxやContextでやる方がいい) */
const [status, setStatus] = React.useState({
open: false,
type: "success",
message: "成功しました。"
});
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setStatus({ ...status, open: false });
};コンポーネントを配置する際は以下のようにopen,handleClose,type,messageを指定します。
typeはsuccess, info, warning, errorの中から指定します。
// PostContainer.js
<React.Fragment>
<PostLayout>
{form}
<ErrorButton setStatus={setStatus} />
</PostLayout>
<SnackBar
open={status.open}
handleClose={handleClose}
type={status.type}
message={status.message}
/>
</React.Fragment>これで準備は出来ました。あとは通信をするときに呼び出すだけです。
onSubmitにて通信前にスピナーを表示、成功か失敗かによってメッセージを表示、最後にスピナーを消します。
// Submitボタンを押したときの処理
const onSubmit = data => {
console.log(data); // 送信するデータ
setProgress(true); // スピナーを表示
axios
.post("posts", data)
.then(response => {
console.log(response);
// 成功のメッセージを表示
setStatus({
open: true,
type: "success",
message: "データの作成に成功しました。"
});
})
.catch(error => {
console.log(error);
// エラーハンドリング
if (error.response) {
setStatus({
open: true,
type: "error",
message: `失敗しました。(コード:${error.response.status})`
});
}
})
.then(() => {
// 常に実行される
setProgress(false); // スピナーを消す
});
};これで完成です。そのままだとAPIが全て成功してしまうので、エラーハンドリングの確認用にボタンを用意しました。
押すと以下のようにエラーメッセージとエラーコードが表示されます。

以上です。
まとめ
今回はReact + Material UIで通信中にスピナーを表示し、通信終了時にメッセージを表示するプログラムを作りました。
いたって単純ですが、よく使うプログラムなのでぜひご活用下さい。

