@tanstack/query-core
Version:
The framework agnostic core that powers TanStack Query
120 lines (106 loc) • 3.5 kB
text/typescript
import { Subscribable } from './subscribable'
type Listener = (online: boolean) => void
type SetupFn = (setOnline: Listener) => (() => void) | undefined
/**
* The `OnlineManager` manages the online state within TanStack Query. It can
* be used to change the default event listeners or to manually change the
* online state.
*
* By default, the `onlineManager` assumes an active network connection, and
* listens to the `online` and `offline` events on the `window` object to
* detect changes.
*/
export class OnlineManager extends Subscribable<Listener> {
#online = true
#cleanup?: () => void
#setup: SetupFn
constructor() {
super()
this.#setup = (onOnline) => {
// addEventListener does not exist in React Native, but window does
// oxlint-disable-next-line typescript/no-unnecessary-condition
if (typeof window !== 'undefined' && window.addEventListener) {
const onlineListener = () => onOnline(true)
const offlineListener = () => onOnline(false)
// Listen to online
window.addEventListener('online', onlineListener, false)
window.addEventListener('offline', offlineListener, false)
return () => {
// Be sure to unsubscribe if a new handler is set
window.removeEventListener('online', onlineListener)
window.removeEventListener('offline', offlineListener)
}
}
return
}
}
protected override onSubscribe(): void {
if (!this.#cleanup) {
this.setEventListener(this.#setup)
}
}
protected override onUnsubscribe() {
if (!this.hasListeners()) {
this.#cleanup?.()
this.#cleanup = undefined
}
}
/**
* `setEventListener` can be used to set a custom event listener that will
* be used to determine the online state. The provided `setup` function
* receives a `setOnline` callback that should be called with a `boolean`
* whenever the online state changes.
* @param setup - Receives the `setOnline` callback, registers the event listener, and may return
* a cleanup function that is called when the listener is replaced or no longer needed.
* @example
* ```ts
* import NetInfo from '@react-native-community/netinfo'
* import { onlineManager } from '@tanstack/query-core'
*
* onlineManager.setEventListener((setOnline) => {
* return NetInfo.addEventListener((state) => {
* setOnline(!!state.isConnected)
* })
* })
* ```
*/
setEventListener(setup: SetupFn): void {
this.#setup = setup
this.#cleanup?.()
this.#cleanup = setup(this.setOnline.bind(this))
}
/**
* `setOnline` can be used to manually set the online state.
* @param online - The online state.
* @example
* ```ts
* import { onlineManager } from '@tanstack/query-core'
*
* // Set to online
* onlineManager.setOnline(true)
*
* // Set to offline
* onlineManager.setOnline(false)
* ```
*/
setOnline(online: boolean): void {
const changed = this.#online !== online
if (changed) {
this.#online = online
this.listeners.forEach((listener) => {
listener(online)
})
}
}
/**
* `isOnline` can be used to get the current online state.
* @returns `true` if online.
*/
isOnline(): boolean {
return this.#online
}
}
/**
* Singleton instance of {@link OnlineManager}, used to manage and observe the online state within TanStack Query.
*/
export const onlineManager = new OnlineManager()