Hi,
Today I would like to share my way of displaying error or custom messages in React.
The idea is to use context and custom hook so we are able to access the component on all pages.
Custom Message Context Provider
Let's create a context provider first.
// CustomMessageProvider.tsx
import { createContext, useState } from 'react';
/*
* show : whether show or hide the message block
* type : what theme is the message block
* msg : message displaying on the message block
*
* You can add more field if you want
*/
interface Msg {
show: boolean;
type: 'error' | 'info' | 'success' | 'warning';
msg: string;
}
const defaultMsg = {
show: false,
type: 'success',
msg: ''
} as Msg
export const CustomMessageContext = createContext({
msg: defaultMsg as Msg,
setMsg: (_: Msg) => {}
})
export const CustomMessageProvider = ({children}) => {
const [msgState, setMsgState] = useState(defaultMsg)
// CustomMessageContext contains an object
// and also a method for setState
const contextValue = {
msg: msgState,
setMsg: (val: Msg) => setMsgState(val)
}
return (
<CustomMessageContext.Provider value={contextValue}>
{children}
</CustomMessageContext.Provider>
);
}
Custom Snackbar
After that, create a custom snackbar using material-ui
// CustomSnackBar.tsx
const CustomSnackBar = () => {
const { msg, setMsg } = useMsg();
return (
<Snackbar
open={msg?.show}
autoHideDuration={3000}
onClose={() => {
setMsg({
show: false,
type: msg.type,
msg: ''
});
}}>
<Alert severity={msg.type}>{msg.msg}</Alert>
</Snackbar>
);
};
const Alert = (props) => {
return (
<MuiAlert
elevation={6}
variant="filled"
{...props}
/>
);
};
export default CustomSnackBar;
Then we can add the provider to App.tsx
so that we can access the context on all pages.
// App.tsx
const App = () => {
<CustomMessageProvider>
...
<CustomSnackBar />
</CustomMessageProvider>
}
export default App
Great!
Custom hook
What we are going to do now is to add a custom hook so we don't have to call useContext in all pages
// customMessageHook.tsx
const useMsg = () => {
const { msg, setMsg } = useContext(CustomMessageContext);
return { msg, setMsg };
}
export default useMsg;
Integration
We can now call useMsg on all pages.
Let say you want to display an error if the fetch API failed on a page.
const { setMsg } = useMsg();
...
const fetchApi = async () => {
try {
...
} catch (err) {
setMsg({
show: true,
type: 'error',
msg: 'Oops, error'
})
}
}
Ending
I know there are some more elegant ways to implement this, feel free to leave me a comment and share what you think.
Have a nice day.
Top comments (3)
This is a really nice pattern! Very useful one.
Nice one
Very helpful