Creating a Simple Toast Component in React with Custom Hooks
But first, what are Custom Hooks?
A Custom Hook is a technique that allows you to encapsulate a component's logic into a reusable function. Custom Hooks are functions in JavaScript that utilize the Hooks provided by React, such as useState, useEffect, useCallback, etc. For a function to be considered a Custom Hook, it must start with the prefix "use" and use at least one React Hook.
Now that we understand what a Custom Hook is, let's apply it to our component. A Toast is a simple component often used to display information to the user after an action. Our goal is to create a Toast that can be reused in any context within the application, providing an efficient and consistent way to show feedback messages to the user.
First Step
First, we'll add a <div> to our root component to serve as the wrapper for our Toast.
function App() {
return (
<>
<div className="App"></div>
<div id="container-toast"></div>
</>
);
}
Custom Hook - useTimeout
Next, we'll create our first Custom Hook, useTimeout. This Custom Hook will be responsible for executing a function provided as a parameter after a specified time interval, also provided as a parameter. We will use the useEffect hook and the setTimeout function from the Web API.
const useTimeout = (callback, delay = 3000, dependencies = []) => {
useEffect(() => {
const timeoutId = setTimeout(() => {
callback()
}, delay)
return () => {
clearTimeout(timeoutId)
}
}, [delay, ...dependencies])
}
Make a Toast Component
Now we need our Toast component.
const ToastComponent = ({ acceptHtml, message, delay, onClose }) => {
useTimeout(
() => {
onClose();
},
delay,
[onClose]
);
if (acceptHtml) {
return <div className={styles.toast} dangerouslySetInnerHTML={{ __html: message }} />;
}
return (
<div className={styles.toast}>
<span>{message}</span>
</div>
);
};
Our component receives 4 props:
领英推荐
We need to add styles to the component. The basic required style is absolute positioning and the placement where you want the toast to appear. Don’t be like me; get creative to enhance the appearance of your component. ??
.toast {
position: absolute;
right: 34px;
width: 200px;
height: 100px;
border: 1px solid red;
}
The function that shows the toast
With the component ready, let's create the function responsible for displaying the toast on the screen.
const showToast = ({ delay = 3000, acceptHtml = false, message }) => {
const container = document.getElementById("container-toast");
const root = createRoot(container);
const handleClose = () => {
const toastElement = document.getElementById("container-toast");
root.unmount(toastElement);
};
const toast = (
<ToastComponent
delay={delay}
onClose={handleClose}
acceptHtml={acceptHtml}
message={message}
/>
);
root.render(toast, container);
};
Our function locates the project's root container, "container-toast," and renders the ToastComponent within it. The handleClose function performs the opposite operation by locating the element in the DOM and removing it. Remember that the onClose prop is executed within our useTimeout. Therefore, when the delay time expires, the component will be removed from the screen. Simple, right?
Usage
And how to use it? You can simply call the showToast function in response to a button click.
unction App() {
return (
<div className="App">
<button onClick={() => { showToast({
message: "Hello! I'm a Toast! "
}) }}>Click me!</button>
<div id="container-toast"></div>
</div>
);
}
We can also create another Custom Hook that will only be executed when a specific condition is true.
const useToast = (conditionShowToast, message, delay, acceptHtml) => {
useEffect(() => {
if(conditionShowToast) {
showToast({
message,
delay,
acceptHtml
})
}
}, [conditionShowToast])
}
Conclusion
Finally, you have a simple Toast ready to be used throughout your application, implemented using the Custom Hook pattern! I’m available for any tips, suggestions for improvements, or comments.
Mobile Engineer | React Native Developer | React | TypeScript | JavaScript | Mobile Developer | Node
7 个月Very informative Otávio Soares!