ライブラリ
- react@18.2.0
- next@14.0.3
- @mui/material@5.14.12
- jotai@2.4.3
フラッシュメッセージとは
例えば、こんなやつ。Webアプリケーションで多数登場することになる。
グローバル関数callFlashMessage
を作成し、プロジェクトのどこからでも呼び出せるようにする。
まずは状態管理
フラッシュメッセージを制御するための情報を状態管理に持たせる。今回は、jotaiライブラリを使う。
import { AlertColor, SnackbarProps } from "@mui/material";
import { atom } from "jotai";
export const snackbarAtom = atom<{severity?: AlertColor, loading: boolean} & SnackbarProps>({
loading: false,
autoHideDuration: 5000,
})
MUIのsnackbar
のpropsに加えて、loadingとserverityプロパティを設定。
loading→trueの場合、サーキュレートインディケータをつけて永久表示させる。デフォルトでは5秒間表示。
serverity→AlertColor
つまり'info' | 'success' | 'warning' | 'error'
の中から色を選べるように。
コンポーネント作成
FlashMessage
コンポーネントを作る。グローバルフラッシュメッセージなるものを作りたいので、コンポーネントはlayout.tsx付近に配置。
'use client'
import { snackbarAtom } from "@/atom/snackbar";
import { Alert, CircularProgress, Slide, Snackbar } from "@mui/material";
import { useAtom } from "jotai";
import { FC, SyntheticEvent, useEffect, useState } from "react";
import { IconButton } from "@mui/material";
import CloseIcon from '@mui/icons-material/Close';
const close = (handleClose) => (
<IconButton
size="small"
onClick={handleClose}
color="inherit"
>
<CloseIcon fontSize="small" />
</IconButton>
)
export const FlashMessage: FC = () => {
const [ { key, loading, children, message, severity, ...props}, setProps ] = useAtom(snackbarAtom)
const defaultDuration = 5000
const [ autoHideDuration, setAutoHideDuration ] = useState(defaultDuration)
useEffect(() => {
setAutoHideDuration(loading ? null : defaultDuration)
}, [ loading ])
const handleClose = (event: SyntheticEvent | Event, reason?: string) => {
if (reason === 'clickaway') {
return;
}
setProps({ key, loading, children, message, severity, ...props, open: false });
}
const action = close(handleClose)
return(
<Snackbar
key={key || 'snackbar'}
action={action}
onClose={handleClose}
autoHideDuration={autoHideDuration}
message={message}
TransitionComponent={(props) => <Slide { ...props } direction="right" />}
{...props}
>{children || severity && (
<Alert
onClose={handleClose}
severity={severity}
sx={{ width: '100%' }}
icon={loading ? <CircularProgress color="inherit" size={22} /> : undefined}
>
{message}
</Alert>
)}</Snackbar>
)
}
callFlashMessageの作成
ここまでで、useAtom
を使いながらグローバルにフラッシュメッセージを呼び出そうと思えば呼び出せる。
import { snackbarAtom } from '@/atom/snackbar.ts'
snaconst [ snackbar, setSnackbar] = useAtom(snackbarAtom)
setSnackbar({
...snackbar,
key: 'flashMessage',
loading: true,
severity: 'info',
message: '〇〇処理を開始しました。',
open: true
})
…が、いちいちsnackbar
のpropsを意識しなといけないので、簡単に呼び出せるよう自作関数callFlashMessage
を作る。
こちらの記事を参考に、まずstore
を設置。
export const store = createStore()
<JotaiProvider store={store}>{children}</JotaiProvider>
store
を使って制御するための関数を作成。
import { store } from '@/components/Atom/Provider'
type Action = 'start' | 'success' | 'fail'
export const callFlashMessage = (action: Action, message: string) => {
let severity;
switch(action) {
case 'start':
severity = 'info';
break;
case 'success':
severity = 'success'
break
case 'fail':
severity = 'error'
break
default:
severity = undefined
break
}
store.set(snackbarAtom, ((prevState) => ({
...prevState,
key: 'flashMessage',
open: true,
loading: action == 'start',
message,
severity
})))
}
引数には、actionとmessageを設定。actionには'start' | 'success' | 'fail'の3種類を許可。正直、フラッシュメッセージの種類としてはたいていこの3つだけでいい。
callFlashMessage('start', '〇〇処理を開始しました。')
callFlashMessage('success', '〇〇処理が完了しました。')
callFlashMessage('fail', '〇〇処理が失敗しました。')
もっとカスタマイズしたければ、自作関数も自由に増やせばいい。