Using AbortController vs removeEventListener
Using AbortController
import { useEffect } from "react"
export function useOnlineStatus(onlineCallback: () => void, offlineCallback: () => void) {
useEffect(() => {
const controller = new AbortController()
window.addEventListener("online", onlineCallback, { signal: controller.signal })
window.addEventListener("offline", offlineCallback, { signal: controller.signal })
return () => {
controller.abort()
}
}, [onlineCallback, offlineCallback])
}
vs
Using removeEventListener
import { useEffect } from 'react';
export function useOnlineStatus(
onlineCallback: () => void,
offlineCallback: () => void
) {
useEffect(() => {
window.addEventListener('online', onlineCallback);
window.addEventListener('offline', offlineCallback);
return () => {
window.removeEventListener('online', onlineCallback);
window.removeEventListener('offline', offlineCallback);
};
}, [onlineCallback, offlineCallback]);
}
Readability
The clean up function ( every re-render and unmounts) of the useEffect can simply call controller.abort()
...
return () => {
controller.abort()
}
...
Issue: Incorrect online status is rendered
For example,
Use the variable returns by the hook useOnlineStatus in the component App
useOnlineStatus.ts
import { useEffect } from "react"
export function useOnlineStatus(onlineCallback: () => void, offlineCallback: () => void) {
useEffect(() => {
const controller = new AbortController()
window.addEventListener("online", onlineCallback, { signal: controller.signal })
window.addEventListener("offline", offlineCallback, { signal: controller.signal })
return () => {
controller.abort()
}
}, [onlineCallback, offlineCallback])
// return the window online status
return navigator.onLine;
}
App.tsx
import React, {useCallback} from 'react';
import { useOnlineStatus } from './hook';
export function App(props) {
const handleOnline = useCallback(() => {
console.log('online');
}, []);
const handleOffline = useCallback(() => {
console.log('offline');
}, []);
const isOnline = useOnlineStatus(handleOnline, handleOffline);
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
<p>Online status: <span>{isOnline.toString()}</span></p>
</div>
);
}
However, when switching between "Offline" and "No throttling" on the "Network" tab of Chrome DevTools, the component application does not display the correct online status isOnline.
See that the value of isOnline is false when the connection status is online:
Root cause
Because only when the component App is rendered, the return value navigator.onLine when calling the hook useOnlineStatus will be assigned to the variable isOnline. However, when the online state changes, the component App will not re-render, which will show the old state of isOnline instead of the current navigator.onLine value in the window.
Solution
Update useOnlineStatus hook to return state variable instead of navigator.onLine.
When the online event is delivered to the target (window), the callback functions onlineCallback and set are called to perform tasks and update the state variables respectively; when the offline event is delivered to the target (window), the working principle is similar.
Declare the state varialbe isOnline
const [isOnline, setIsOnline] = useState(true);
Full codes
import { useEffect, useState, useCallback } from 'react';
export function useOnlineStatus(
onlineCallback: () => void,
offlineCallback: () => void
) {
const [isOnline, setIsOnline] = useState(true);
const handleOnline = useCallback(() => {
onlineCallback();
setIsOnline(true);
}, []);
const handleOffline = useCallback(() => {
offlineCallback();
setIsOnline(false);
}, []);
useEffect(() => {
const controller = new AbortController();
window.addEventListener('online', handleOnline, {
signal: controller.signal,
});
window.addEventListener('offline', handleOffline, {
signal: controller.signal,
});
return () => {
controller.abort();
};
}, [onlineCallback, offlineCallback]);
return isOnline;
}
In this way, when the online/offline status changes, the component App using the useOnlineStatus hook will re-render and display the correct online status.

Top comments (2)
This is great code. Thank you for you trouble.
I wanna know about controller function in more detail.
Thank you :) You can take a look at this page to learn more if you are interested in developer.mozilla.org/en-US/docs/W...