今回は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で通信中にスピナーを表示し、通信終了時にメッセージを表示するプログラムを作りました。
いたって単純ですが、よく使うプログラムなのでぜひご活用下さい。