diff --git a/README.md b/README.md
index 0670c3f..f7c33a0 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,20 @@
Add React Native + React Navigation compatibility to [`swr`](https://swr.vercel.app). 👨🏻🔧
-```diff
-- import useSWR from 'swr'
-+ import useSWRNative from '@nandorojo/swr-react-native'
+```typescript
+import { swrNativeMiddleware } from '@nandorojo/swr-react-native'
+
+function App() {
+ return (
+
+ {
+ // That's it!
+ }
+
+ )
+}
```
-**That's it.**
-
SWR revalidation now works in your React Native app. Requests also revalidate when your React Navigation screens focus.
## Why?
@@ -17,20 +24,19 @@ SWR revalidation now works in your React Native app. Requests also revalidate wh
However, some of its essential features, such as `revalidateOnFocus` & `revalidateOnConnect`, don't work on React Native.
-This library provides a simple drop-in replacement for `useSWR`, which adds compatibility for **React Native** / **React Navigation**.
-
-It comes with 2 hooks: `useSWRNative`, and `useSWRNativeRevalidate`.
+This library provides a middleware `swrNativeMiddleware` for `useSWR`, which adds compatibility for **React Native** / **React Navigation**.
## Features
- Adds support for `revalidateOnConnect` & `revalidateOnFocus`.
+- Adds support for `refreshInterval` & `refreshWhenHidden`.
- Configurable `focusEventThrottle`
- Web, iOS and Android support
- Zero config
- Revalidates when `AppState` becomes `active`
- Works with **React Navigation**, revalidating on screen `focus`
- TypeScript support
-- `useSWRInfinite` support
+- `useSWRInfinite` & and `useSWRImmutable` support
## Installation
@@ -48,72 +54,71 @@ expo install @react-native-community/netinfo
yarn add @react-native-community/netinfo
```
-### Usage with SWR v1
+## Migration from swr-react-native v1
+
+V2 is now implemented as a swr middleware to support `refreshInterval` option ([details](https://github.com/nandorojo/swr-react-native/issues/22)).
-Currently, SWR v1 is in `beta`:
+The migration to the new middleware API is pretty straightforward and is recommended. We still maintain backward-compatible APIs such as `useSWRNative` and `useSWRNativeRevalidate` for ease of migration, but those previous APIs do not support `refreshInterval` option and are not recommended.
+
+**If you plan to combine useSWRNative / useSWRNativeRevalidate and the new middleware instead of fully migrating to the new middleware API, you need to be aware of the potential double-calling issue. Please refer to [this comment](https://github.com/nandorojo/swr-react-native/pull/25#issuecomment-1420728115) for more information.**
+
+### Usage with SWR v1
```sh
-yarn add swr@beta
+yarn add swr
```
-To use `swr-react-native`, you can install with `@beta` too:
+To use `swr-react-native`, you can install with the following command:
```sh
-yarn add @nandorojo/swr-react-native@beta
+yarn add @nandorojo/swr-react-native
```
## Usage
There are 2 ways to use this library:
-### 1. Simplest usage
+### 1. Global Configuration (Recommended)
-Replace imports of `useSWR` with `useSWRNative`. That's it!
+Add a SWRConfig Provider with the middleware at the top of the App. That's it!
-```ts
-import useSWRNative from '@nandorojo/swr-react-native'
+```tsx
+// in App.tsx
+import { swrNativeMiddleware } from '@nandorojo/swr-react-native'
-const { data, mutate, error } = useSWRNative(key, fetcher, config)
-```
+function App() {
+ return
+ {...}
+
+}
-### 2. Custom usage
+// now anywhere inside App
+const { data, mutate, error } = useSWR(key, fetcher, config)
+```
-If, for some reason, you don't want to replace your imports, you can use the `useSWRNativeRevalidate` hook. This allows you to de-couple the revalidation from the `useSWR` hook itself.
+### 2. Per-Hook Usage
-This option exists in case `useSWR` makes some big changes to their API or something down the line. Or, maybe you're using React Native web, and not all screens are nested in a React Navigation stack, so you want to call this only in those places.
+If, for some reason, you don't want to set up this library globally, you can also use the `use` option in `useSWR`'s `config`
-If you're using `useSWRInfinite`, then this is the method for you.
+This option is useful if you're using React Native web, and not all screens are nested in a React Navigation stack, so you want to call this only in those places.
```ts
-import { useSWRNativeRevalidate } from '@nandorojo/swr-react-native'
+import { swrNativeMiddleware } from '@nandorojo/swr-react-native'
```
-Call `useSWRNativeRevalidate`, likely below your `useSWR` function:
+Use `swrNativeMiddleware`, in `useSWR` config:
```ts
-const { data, mutate } = useSWR(key, fetcher)
-
-useSWRNativeRevalidate({
- // required: pass your mutate function returned by SWR
- mutate
-
- // optional, defaults copied from SWR
- revalidateOnFocus: true,
- revalidateOnReconnect: true,
- focusThrottleInterval: 5000,
+const { data, mutate } = useSWR(key, fetcher, {
+ use: [swrNativeMiddleware],
})
```
-The `mutate` function is required!
-
-If you're using `useSWRInfinite`, this you should rely on this usage:
+If you're using `useSWRInfinite`, you can use like this:
```ts
-const { data, mutate } = useSWRInfinite(...)
-
-useSWRNativeRevalidate({
- // required: pass your mutate function returned by SWR
- mutate
+const { data, mutate } = useSWRInfinite(getKey, fetcher, {
+ use: [swrNativeMiddleware],
})
```
diff --git a/src/index.ts b/src/index.ts
index efdc92d..67b3d36 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'
@@ -19,10 +19,47 @@ 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
@@ -138,7 +175,7 @@ export function useSWRNativeRevalidate(
type Fetcher = ((...args: any) => Data | Promise) | null
-const useSWRNative = (
+export const useSWRNative = (
key: Key,
fn: Fetcher = null,
config?: SWRConfiguration
@@ -155,4 +192,9 @@ const useSWRNative = (
return swr
}
+/**
+ * swr-react-native
+ *
+ * This hook is not recommended to be used any more but is exported anyway for compatibility.
+ */
export default useSWRNative