I have a helper function checkOnline, with a function which tests whether my app is online or offline. I then have a component with a modal. I want to update the state of this modal depending on whether the user is online or not. If he is offline I want to make the modal disapear. I am not sure on how to call the function, if the eventlistenner is taken into account. I also do not want to call the function on repeat. Maybe I have to put it in a useEffect. The goal is to run the function depending on wether the addeventlistenner changes from online to offline...
checkOnline.js
export const isOnline = async () => {
if (!window.navigator.onLine) return false;
// avoid CORS errors with a request to your own origin
const url = new URL(window.location.origin);
// random value to prevent cached responses
url.searchParams.set('rand', Date.now());
try {
const response = await fetch(url.toString(), { method: 'HEAD' });
return response.ok;
} catch {
return false;
}
};
window.addEventListener('online', () => console.log('online'));
window.addEventListener('offline', () => console.log('offline'));
App.js
import { isOnline } from "../../helpers/CheckOnline";
export default function App() {
const [isModalVisible, setIsModalVisible] = useState(false);
const modal = async () => {
const online = await isOnline();
if (!online) {
setIsModalVisible(false);
}
};
modal();
return (
<div className="App">
<Modal centered visible={isModalVisible}>
<p>test</p>
</Modal>
</div>
);
}
CodePudding user response:
You should use the addEventListener
and removeEventListener
in an useEffect
to prevent adding a listener, everytime a rerender happens. A solution therefore might be this one. It's basically the same you already have, with small changes:
import { useCallback, useEffect, useState } from "react";
export const isOnline = async () => {
if (!window.navigator.onLine) return false;
// avoid CORS errors with a request to your own origin
const url = new URL(window.location.origin);
// random value to prevent cached responses
url.searchParams.set("rand", Date.now());
try {
const response = await fetch(url.toString(), { method: "HEAD" });
return response.ok;
} catch {
return false;
}
};
// simple indicator whether it works or doesn't
const Modal = ({ visible }) => (visible ? <div>Modal</div> : null);
export default function App() {
const [isModalVisible, setIsModalVisible] = useState(false);
const isOnlineHandler = useCallback(async () => {
const online = await isOnline();
if (!online) {
setIsModalVisible(false);
}
}, []);
useEffect(() => {
window.addEventListener("online", isOnlineHandler);
return () => {
window.addEventListener("offline", isOnlineHandler);
};
}, [isOnlineHandler]);
return (
<div className="App">
<Modal centered visible={isModalVisible}>
<p>test</p>
</Modal>
</div>
);
}
To have a working example, I've added a simplified Modal
component.
CodePudding user response:
U can use this custom hook. Check if is online / offline with event and navigator.
On sandbox u can test it with offline mode in Chrome
https://codesandbox.io/s/snowy-cherry-z1hlvi
export const useIsOnline = () => {
const [online, setOnline] = useState(window.navigator.onLine)
const checkOnline = useCallback(async () => {
const url = new URL(window.location.origin);
// random value to prevent cached responses
url.searchParams.set('rand', Date.now());
try {
const response = await fetch(url.toString(), { method: 'HEAD' });
setOnline(response.ok);
} catch {
setOnline(false)
}
}, [])
useEffect(() => {
const offlineCallback = () => setOnline(false)
window.addEventListener('online', checkOnline);
window.addEventListener('offline', offlineCallback);
return () => {
window.removeEventListener('online', checkOnline)
window.removeEventListener('offline', offlineCallback)
}
}, [checkOnline])
return online
}