|
/** |
|
* Author: @nandorojo, adapted from https://github.com/vercel/swr/issues/417#issuecomment-721438386 |
|
* Forces SWR to revalidate when one of the following events occurs |
|
* - React-Navigation event (focus) |
|
* - Focus of the app through AppState is propagated |
|
* - Networks access is restored |
|
*/ |
|
import { responseInterface, ConfigInterface } from 'swr'; |
|
import { useRef, useEffect } from 'react'; |
|
import { AppState } from 'react-native'; |
|
import { useNavigation } from '@react-navigation/native'; |
|
import NetInfo, { NetInfoState } from '@react-native-community/netinfo'; |
|
|
|
type Props<Data, Error> = { |
|
/** |
|
* Required: pass the `revalidate` function returned to you by SWR. |
|
*/ |
|
revalidate: responseInterface<Data, Error>['revalidate']; |
|
} & Pick< |
|
ConfigInterface, |
|
'revalidateOnFocus' | 'revalidateOnReconnect' | 'focusThrottleInterval' |
|
>; |
|
|
|
import { Platform } from 'react-native'; |
|
|
|
/** |
|
* swr-react-native |
|
* |
|
* This helps you revalidate your SWR calls, based on navigation actions in `react-navigation`. |
|
*/ |
|
export default function useSWRReactNavigation<Data = any, Error = any>( |
|
props: Props<Data, Error>, |
|
) { |
|
const { |
|
revalidate, |
|
// copy defaults from SWR |
|
revalidateOnFocus = true, |
|
revalidateOnReconnect = true, |
|
focusThrottleInterval = 5000, |
|
} = props; |
|
|
|
const { addListener } = useNavigation(); |
|
|
|
const lastFocusedAt = useRef<number | null>(null); |
|
const focusCount = useRef<number>(0); |
|
const fetchRef = useRef(revalidate); |
|
useEffect(() => { |
|
fetchRef.current = revalidate; |
|
}); |
|
|
|
const previousAppState = useRef(AppState.currentState); |
|
const previousNetworkState = useRef<NetInfoState | null>(null); |
|
|
|
useEffect(() => { |
|
// SWR does all of this on web. |
|
if (Platform.OS === 'web') return; |
|
|
|
let unsubscribeReconnect: ReturnType< |
|
typeof NetInfo.addEventListener |
|
> | null = null; |
|
if (revalidateOnReconnect) { |
|
unsubscribeReconnect = NetInfo.addEventListener((state) => { |
|
if ( |
|
previousNetworkState.current?.isInternetReachable === false && |
|
state.isConnected && |
|
state.isInternetReachable |
|
) { |
|
fetchRef.current(); |
|
} |
|
previousNetworkState.current = state; |
|
}); |
|
} |
|
|
|
const onFocus = () => { |
|
// First focus is replaced by SWR's first load event |
|
if (focusCount.current < 1) { |
|
focusCount.current = 1; |
|
return; |
|
} |
|
const isThrottled = |
|
focusThrottleInterval && |
|
lastFocusedAt.current && |
|
Date.now() - lastFocusedAt.current <= focusThrottleInterval; |
|
|
|
if (!isThrottled) { |
|
lastFocusedAt.current = Date.now(); |
|
fetchRef.current(); |
|
} |
|
}; |
|
|
|
const onAppStateChange = (nextAppState: AppState['currentState']) => { |
|
if ( |
|
previousAppState.current.match(/inactive|background/) && |
|
nextAppState === 'active' |
|
) { |
|
onFocus(); |
|
} |
|
|
|
previousAppState.current = nextAppState; |
|
}; |
|
|
|
let unsubscribeFocus: ReturnType<typeof addListener> | null = null; |
|
|
|
if (revalidateOnFocus) { |
|
unsubscribeFocus = addListener('focus', onFocus); |
|
AppState.addEventListener('change', onAppStateChange); |
|
} |
|
|
|
return () => { |
|
if (revalidateOnFocus) { |
|
unsubscribeFocus?.(); |
|
AppState.removeEventListener('change', onAppStateChange); |
|
} |
|
if (revalidateOnReconnect) { |
|
unsubscribeReconnect?.(); |
|
} |
|
}; |
|
}, [ |
|
addListener, |
|
focusThrottleInterval, |
|
revalidateOnFocus, |
|
revalidateOnReconnect, |
|
]); |
|
} |
I believe line 76 should read
=== 0
, right? Or<1