diff --git a/README.md b/README.md index 0f605e31..e1f9723a 100644 --- a/README.md +++ b/README.md @@ -102,17 +102,20 @@ import NetInfo from "@react-native-community/netinfo"; Note that the API was updated after it was extracted from NetInfo to support some new features, however, the previous API is still available and works with no updates to your code. ## Usage -Import the library: -```javascript -import NetInfo from "@react-native-community/netinfo"; -``` +### Global vs isolated instance +Internally this library has a network state manager class to handle all the functionality and state. This library provides two options for instantiating the class: +1. you can use global library functions which taps into a global singleton instance of the class +2. or you can create isolated instances of the class to tap into, each being separately configured +### Global instance functions: Subscribe to network state updates: ```javascript +import { addEventListener } from "@react-native-community/netinfo"; + // Subscribe -const unsubscribe = NetInfo.addEventListener(state => { +const unsubscribe = addEventListener(state => { console.log("Connection type", state.type); console.log("Is connected?", state.isConnected); }); @@ -124,22 +127,43 @@ unsubscribe(); Get the network state once: ```javascript -NetInfo.fetch().then(state => { +import { fetch } from "@react-native-community/netinfo"; + +fetch().then(state => { console.log("Connection type", state.type); console.log("Is connected?", state.isConnected); }); ``` +Get network state updates from the global instance via a react hook: + +```javascript +import { useNetInfo } from "@react-native-community/netinfo"; + +const { type, isConnected } = useNetInfo(); +``` + +### Isolated instance: +Use an isolated instance of the network manager: + +```javascript +import { useNetInfoInstance } from "@react-native-community/netinfo"; + +const { netInfo: { type, isConnected }, refresh } = useNetInfoInstance(); +``` + ## API * **Types:** * [`NetInfoState`](#netinfostate) * [`NetInfoStateType`](#netinfostatetype) * [`NetInfoCellularGeneration`](#netinfocellulargeneration) -* **Methods:** +* **Global instance methods:** * [`fetch()`](#fetch) * [`refresh()`](#refresh) * [`addEventListener()`](#addeventlistener) * [`useNetInfo()`](#usenetinfo) +* **Isolated instance:** + * [`useNetInfoInstance()`](#usenetinfoinstance) ### Types @@ -241,7 +265,9 @@ The configuration options for the library. | `useNativeReachability` | `boolean` | `true` | A flag indicating whether or not Netinfo should use native reachability checks, if available. -### Methods +### Global instance methods + +Please note the difference between global and isolated usage described [here](#global-vs-isolated-instance) #### `configure()` @@ -285,7 +311,7 @@ unsubscribe(); #### `useNetInfo()` -A [React Hook](https://reactjs.org/docs/hooks-intro.html) which can be used to get access to the latest state. It returns a hook with the [`NetInfoState`](README.md#netinfostate) type. +A [React Hook](https://reactjs.org/docs/hooks-intro.html) which can be used to get access to the latest state from the global instance. It returns a hook with the [`NetInfoState`](README.md#netinfostate) type. **Example:** ```jsx @@ -358,6 +384,54 @@ NetInfo.refresh().then(state => { This will also update subscribers using `addEventListener` and/or `useNetInfo`. +### Isolated instance + +Please note the difference between global and isolated usage described [here](#global-vs-isolated-instance) + +#### `useNetInfoInstance()` + +A [React Hook](https://reactjs.org/docs/hooks-intro.html) which can be used to create and manage an isolated instance of a network manager class. It returns a `refresh` function and the current [`NetInfoState`](README.md#netinfostate). + +**Example:** +```jsx +import { useNetInfoInstance } from "@react-native-community/netinfo"; + +const YourComponent = () => { + const {netInfo, refresh} = useNetInfoInstance(); + + return ( + + Type: {netInfo.type} + Is Connected? {netInfo.isConnected?.toString()} + + ); +}; +``` + +**isPaused**: You can also pause the hooks internal network checks by passing a boolean value `true` as the first argument. + +**configuration**: You can optionally send configuration as the second argument when setting up the hook. Note that configuration is local to the instance managed by this hook and has no relation to the configuration passed to other functions `configure()` or `useNetInfo()`; + +```jsx +import { useNetInfoInstance } from "@react-native-community/netinfo"; + +const YourComponent = () => { + const isPaused = false; + const config = { + reachabilityUrl: 'https://clients3.google.com/generate_204', + reachabilityTest: async (response) => response.status === 204, + reachabilityLongTimeout: 60 * 1000, // 60s + reachabilityShortTimeout: 5 * 1000, // 5s + reachabilityRequestTimeout: 15 * 1000, // 15s + reachabilityShouldRun: () => true, + shouldFetchWiFiSSID: true, // met iOS requirements to get SSID + useNativeReachability: false + } + + const { netInfo } = useNetInfoInstance(isPaused, config); + //... +``` + ## Troubleshooting ### Errors when building on Android diff --git a/src/index.ts b/src/index.ts index 6e8a197d..910b88d6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ * @format */ -import {useState, useEffect} from 'react'; +import {useState, useEffect, useCallback} from 'react'; import {Platform} from 'react-native'; import DEFAULT_CONFIGURATION from './internal/defaultConfiguration'; import NativeInterface from './internal/nativeInterface'; @@ -26,7 +26,7 @@ const createState = (): State => { /** * Configures the library with the given configuration. Note that calling this will stop all * previously added listeners from being called again. It is best to call this right when your - * application is started to avoid issues. + * application is started to avoid issues. The configuration sets up a global singleton instance. * * @param configuration The new configuration to set. */ @@ -50,6 +50,7 @@ export function configure( /** * Returns a `Promise` that resolves to a `NetInfoState` object. + * This function operates on the global singleton instance configured using `configure()` * * @param [requestedInterface] interface from which to obtain the information * @@ -65,7 +66,7 @@ export function fetch( } /** - * Force-refreshes the internal state of the NetInfo library. + * Force-refreshes the internal state of the global singleton managed by this library. * * @returns A Promise which contains the updated connection state. */ @@ -77,7 +78,7 @@ export function refresh(): Promise { } /** - * Subscribe to connection information. The callback is called with a parameter of type + * Subscribe to the global singleton's connection information. The callback is called with a parameter of type * [`NetInfoState`](README.md#netinfostate) whenever the connection state changes. Your listener * will be called with the latest information soon after you subscribe and then with any * subsequent changes afterwards. You should not assume that the listener is called in the same @@ -101,7 +102,9 @@ export function addEventListener( } /** - * A React Hook which updates when the connection state changes. + * A React Hook into this library's singleton which updates when the connection state changes. + * + * @param {Partial} configuration - Configure the isolated network checker managed by this hook * * @returns The connection state. */ @@ -126,6 +129,51 @@ export function useNetInfo( return netInfo; } +/** + * A React Hook which manages an isolated instance of the network info manager. + * This is not a hook into a singleton shared state. NetInfo.configure, NetInfo.addEventListener, + * NetInfo.fetch, NetInfo.refresh are performed on a global singleton and have no affect on this hook. + * @param {boolean} isPaused - Pause the internal network checks. + * @param {Partial} configuration - Configure the isolated network checker managed by this hook + * + * @returns the netInfo state and a refresh function + */ +export function useNetInfoInstance( + isPaused = false, + configuration?: Partial, +) { + const [networkInfoManager, setNetworkInfoManager] = useState(); + const [netInfo, setNetInfo] = useState({ + type: Types.NetInfoStateType.unknown, + isConnected: null, + isInternetReachable: null, + details: null, + }); + + useEffect(() => { + if (isPaused) { + return; + } + const config = { + ...DEFAULT_CONFIGURATION, + ...configuration, + }; + const state = new State(config); + setNetworkInfoManager(state); + state.add(setNetInfo); + return state.tearDown; + }, [isPaused, configuration]); + + const refresh = useCallback(() => { + networkInfoManager && networkInfoManager._fetchCurrentState(); + }, [networkInfoManager]); + + return { + netInfo, + refresh, + }; +} + export * from './internal/types'; export default { @@ -134,4 +182,5 @@ export default { refresh, addEventListener, useNetInfo, + useNetInfoInstance, };