In the last episode of the Custom React Hooks series, we've implemented the useLocalStorage hook to simplify local storage management. In today's episode, we'll create a hook to simplify the observation of our users network state: useNetworkState
.
Motivation
Let's say you're building an application that requires to be online in order to work correctly. If the user gets disconnected, you want to display a toast message informing it to check its network connectivity. To do this in a React app, here's how you could proceed:
const App = () => {
const [isOnline, setIsOnline] = useState(window.navigator.onLine);
useEffect(() => {
const handleOnline = () => {
setIsOnline(true);
};
const handleOffline = () => {
setIsOnline(false);
};
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return (
<div>
<h1>My Awesome App</h1>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa
provident tenetur molestias fugiat expedita quaerat dolores dignissimos
dicta, error amet reiciendis voluptates delectus perspiciatis dolorum
saepe, sunt, similique vitae illo.
</p>
{!isOnline && (
<div className="toast">
You are offline. Please check your connectivity and try again.
</div>
)}
</div>
);
};
This works fine, but this is already a lot of code, and above all a lot of logic just inside the useEffect
hook. Our goal is to define a useNetworkState
hook that will abstract this logic inside a custom hook, that is reusable over the entire app to listen for network state changes. This will also reduce the code inside our App
component, that could quickly get longer and longer if we add some other logic (click listeners, form submission, keyboard listeners...).
Implementation
As always, let's think about the interface of our hook (how we are going to use it). In our case, we could have something as simple as this one-liner:
const isOnline = useNetworkState()
Pretty straightforward. This hook would return a single boolean value that gets updated accordingly to synchronize with the network status.
We can already dive into the hook's implementation, by only extracting the logic we've written in the useEffect
hook of our App
component. At the end, the hook will look like this:
const useNetworkState = () => {
const [isOnline, setIsOnline] = useBoolean(window.navigator.onLine);
useEffect(() => {
window.addEventListener('online', setIsOnline.on);
window.addEventListener('offline', setIsOnline.off);
return () => {
window.removeEventListener('online', setIsOnline.on);
window.removeEventListener('offline', setIsOnline.off);
};
}, []);
return isOnline;
};
Wait, what the heck is useBoolean
? This hook doesn't exist... π€¨
Yes, you're right. However, if you've been following this series from the very first episode, this hook might remind you something... as it is the first custom hook we've implemented! If you've discovered this series on the way, no problem: just head over to this link, that will bring you to my article on the useBoolean
hook.
Note: if you don't want to use the
useBoolean
hook, you can be satisfied with the nativeuseState
one, anduseNetworkState
would be the following:const useNetworkState = () => { const [isOnline, setIsOnline] = useState(window.navigator.onLine); useEffect(() => { const handleOnline = () => { setIsOnline(true); }; const handleOffline = () => { setIsOnline(false); }; window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return isOnline; };
Usage
Back to our App
component, where we can drastically simplify the code (see by yourself):
const App = () => {
const isOnline = useNetworkState()
return (
<div>
<h1>My Awesome App</h1>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa
provident tenetur molestias fugiat expedita quaerat dolores dignissimos
dicta, error amet reiciendis voluptates delectus perspiciatis dolorum
saepe, sunt, similique vitae illo.
</p>
{!isOnline && (
<div className="toast">
You are offline. Please check your connectivity and try again.
</div>
)}
</div>
);
};
Yes, yes. One-line. Awesome, right? π
All the logic is now abstracted outside of the component, that only focuses on what matters to it. By doing this, we're following the SOC (Separation of Concerns) design principle β more information here.
Conclusion
I hope this hook will be useful to you for your projects. If you have any questions, feel free to ask them in the comments section. For now, thanks for reading me, and see you next time for a new custom hook. π€
Source code available on CodeSanbox.
Support Me
If you wish to support me, you can click the following link to buy me a coffee (which I will then probably turn into a new custom hook... β).
Top comments (3)
Very useful, thank you!
You're most welcome. ππ»
Some comments may only be visible to logged-in visitors. Sign in to view all comments.