Skip to content

Commit

Permalink
pull in middleware from PR
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackman3005 committed Jul 19, 2023
1 parent bcdcddd commit 4326f2e
Showing 1 changed file with 70 additions and 28 deletions.
98 changes: 70 additions & 28 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -11,21 +11,58 @@ type Props<Data, Error> = {
*/
mutate: SWRResponse<Data, Error>['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<Data = any, Error = any>(
props: Props<Data, Error>
props: Props<Data, Error>
) {
const {
mutate,
Expand All @@ -43,30 +80,30 @@ export function useSWRNativeRevalidate<Data = any, Error = any>(
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)
const previousNetworkState = useRef<NetInfoState | null>(null)

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()
}
Expand All @@ -80,9 +117,9 @@ export function useSWRNativeRevalidate<Data = any, Error = any>(
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()
Expand All @@ -92,10 +129,10 @@ export function useSWRNativeRevalidate<Data = any, Error = any>(

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()
}
Expand All @@ -109,8 +146,8 @@ export function useSWRNativeRevalidate<Data = any, Error = any>(
if (revalidateOnFocus) {
unsubscribeFocus = addListener('focus', onFocus)
unsubscribeAppStateChange = AppState.addEventListener(
'change',
onAppStateChange
'change',
onAppStateChange
)
}

Expand Down Expand Up @@ -138,10 +175,10 @@ export function useSWRNativeRevalidate<Data = any, Error = any>(

type Fetcher<Data> = ((...args: any) => Data | Promise<Data>) | null

const useSWRNative = <Data = any, Error = any>(
key: Key,
fn: Fetcher<Data> = null,
config?: SWRConfiguration<Data, Error>
export const useSWRNative = <Data = any, Error = any>(
key: Key,
fn: Fetcher<Data> = null,
config?: SWRConfiguration<Data, Error>
) => {
const swr = useSWR<Data, Error>(key, fn, config)

Expand All @@ -155,4 +192,9 @@ const useSWRNative = <Data = any, Error = any>(
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

0 comments on commit 4326f2e

Please sign in to comment.