From 4326f2e1122f7028350cfcb9e692537caddee573 Mon Sep 17 00:00:00 2001 From: Jack Coy Date: Wed, 19 Jul 2023 14:52:37 +1000 Subject: [PATCH] pull in middleware from PR - https://github.com/nandorojo/swr-react-native/pull/25 --- src/index.ts | 98 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 28 deletions(-) diff --git a/src/index.ts b/src/index.ts index efdc92d..0023008 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import useSWR, { SWRResponse, SWRConfiguration, Key } from 'swr' +import useSWR, { SWRResponse, SWRConfiguration, Key, Middleware } from 'swr' import { useRef, useEffect } from 'react' import { AppState, Platform } from 'react-native' import { useNavigation } from '@react-navigation/native' @@ -11,21 +11,58 @@ type Props = { */ mutate: SWRResponse['mutate'] } & Pick< - SWRConfiguration, - 'revalidateOnFocus' | 'revalidateOnReconnect' | 'focusThrottleInterval' + SWRConfiguration, + 'revalidateOnFocus' | 'revalidateOnReconnect' | 'focusThrottleInterval' > interface AppStateAddEventListenerReturn { remove: () => void } +/** + * swr-react-native + * + * This is the preferred way to configure swr for react-native. + * This supports avoiding unnecessary refreshes in nested screens when refreshInterval is set. + * + */ +export const swrNativeMiddleware: Middleware = (useSWRNext) => { + return (key, fetcher, config) => { + const navigation = useNavigation() + + const swr = useSWRNext(key, fetcher, { + ...config, + isPaused() { + const isPaused = config.isPaused?.() ?? false + + // do not override if explicitly set to pause + if (isPaused) { + return true + } + + return !config.refreshWhenHidden && !navigation.isFocused() + }, + }) + + useSWRNativeRevalidate({ + mutate: swr.mutate, + revalidateOnFocus: config.revalidateOnFocus, + revalidateOnReconnect: config.revalidateOnReconnect, + focusThrottleInterval: config.focusThrottleInterval, + }) + + return swr + } +} + /** * swr-react-native * * This helps you revalidate your SWR calls, based on navigation actions in `react-navigation`. + * This hook is not recommended to be used directly but is exported anyway for compatibility. */ export function useSWRNativeRevalidate( - props: Props + props: Props ) { const { mutate, @@ -43,11 +80,11 @@ export function useSWRNativeRevalidate( fetchRef.current = mutate }) const focusCount = useRef( - Platform.select({ - // react-navigation fire a focus event on the initial mount, but not on web - web: 1, - default: 0, - }) + Platform.select({ + // react-navigation fire a focus event on the initial mount, but not on web + web: 1, + default: 0, + }) ) const previousAppState = useRef(AppState.currentState) @@ -55,18 +92,18 @@ export function useSWRNativeRevalidate( useEffect(() => { let unsubscribeReconnect: ReturnType< - typeof NetInfo.addEventListener + typeof NetInfo.addEventListener > | null = null if (revalidateOnReconnect && Platform.OS !== 'web') { // inline require to avoid breaking SSR when window doesn't exist const Network: typeof NetInfo = require('@react-native-community/netinfo') - .default + .default // SWR does all of this on web. unsubscribeReconnect = Network.addEventListener((state) => { if ( - previousNetworkState.current?.isInternetReachable === false && - state.isConnected && - state.isInternetReachable + previousNetworkState.current?.isInternetReachable === false && + state.isConnected && + state.isInternetReachable ) { fetchRef.current() } @@ -80,9 +117,9 @@ export function useSWRNativeRevalidate( return } const isThrottled = - focusThrottleInterval && - lastFocusedAt.current && - Date.now() - lastFocusedAt.current <= focusThrottleInterval + focusThrottleInterval && + lastFocusedAt.current && + Date.now() - lastFocusedAt.current <= focusThrottleInterval if (!isThrottled) { lastFocusedAt.current = Date.now() @@ -92,10 +129,10 @@ export function useSWRNativeRevalidate( const onAppStateChange = (nextAppState: AppState['currentState']) => { if ( - previousAppState.current.match(/inactive|background/) && - nextAppState === 'active' && - // swr handles this on web. - Platform.OS !== 'web' + previousAppState.current.match(/inactive|background/) && + nextAppState === 'active' && + // swr handles this on web. + Platform.OS !== 'web' ) { onFocus() } @@ -109,8 +146,8 @@ export function useSWRNativeRevalidate( if (revalidateOnFocus) { unsubscribeFocus = addListener('focus', onFocus) unsubscribeAppStateChange = AppState.addEventListener( - 'change', - onAppStateChange + 'change', + onAppStateChange ) } @@ -138,10 +175,10 @@ export function useSWRNativeRevalidate( type Fetcher = ((...args: any) => Data | Promise) | null -const useSWRNative = ( - key: Key, - fn: Fetcher = null, - config?: SWRConfiguration +export const useSWRNative = ( + key: Key, + fn: Fetcher = null, + config?: SWRConfiguration ) => { const swr = useSWR(key, fn, config) @@ -155,4 +192,9 @@ const useSWRNative = ( return swr } -export default useSWRNative +/** + * swr-react-native + * + * This hook is not recommended to be used any more but is exported anyway for compatibility. + */ +export default useSWRNative \ No newline at end of file