website

#astro#js#html#css

git clone https://git.pyrossh.dev/website

木 Personal website of pyrossh. Built with astrojs, shiki, vite.


src/posts/react-powertools-swr.md
2f32cac 1
---
2f32cac 2
title: "React Powertools: SWR"
2f32cac 3
description: A react library that makes it easier to fetch data
2f32cac 4
pubDate: 2024-08-16
2f32cac 5
tags:
2f32cac 6
  - react
2f32cac 7
  - frontend
2f32cac 8
  - hooks
2f32cac 9
  - swr
2f32cac 10
  - fetch
2f32cac 11
published: true
2f32cac 12
---
2f32cac 13
2f32cac 14
The **SWR** library provides hooks which help in facilitating fetching and revalidating data so that the UI will be always fast and reactive. It uses the stale-while-revalidate, a HTTP cache invalidation strategy, to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data.
2f32cac 15
2f32cac 16
You can install it using this command: `npm i swr`
2f32cac 17
2f32cac 18
### useSWR
2f32cac 19
2f32cac 20
This hook exposes few options to customise the fetching/revalidation logic,
2f32cac 21
2f32cac 22
```tsx
2f32cac 23
const { data, error, isLoading, isValidating, mutate } = useSWR(key, fetcher, options);
2f32cac 24
```
2f32cac 25
2f32cac 26
**Parameters**
2f32cac 27
2f32cac 28
- `key`: a unique key string for the request
2f32cac 29
- `fetcher`: a Promise-returning function to fetch your data
2f32cac 30
- `options`: an object of options for this SWR hook
2f32cac 31
2f32cac 32
**Return values**
2f32cac 33
2f32cac 34
- `data`: data for the given key resolved by `fetcher`
2f32cac 35
- `error`: error thrown by `fetcher`
2f32cac 36
- `isLoading`: if there's an ongoing request and no "loaded data" or state data
2f32cac 37
- `isValidating`: if there's a revalidation request happening
2f32cac 38
- `mutate(data?, options?)`: function to mutate the cached data
2f32cac 39
2f32cac 40
> Before SWR
2f32cac 41
2f32cac 42
```tsx
2f32cac 43
import { useState, useEffect } from "react";
2f32cac 44
2f32cac 45
const useUser = (id: string) => {
2f32cac 46
  const [user, setUser] = useState(null);
2f32cac 47
  const [loading, setLoading] = useState(false);
2f32cac 48
  const [error, setError] = useState(null);
2f32cac 49
2f32cac 50
  useEffect(() => {
2f32cac 51
    setLoading(true);
2f32cac 52
    setError(null);
2f32cac 53
    fetch(`/users/${id}`)
2f32cac 54
      .then((res) => res.json())
2f32cac 55
      .then((data) => {
2f32cac 56
        setUser(data);
2f32cac 57
        setLoading(false);
2f32cac 58
      })
2f32cac 59
      .catch((err) => {
2f32cac 60
        setError(err);
2f32cac 61
        setLoading(false);
2f32cac 62
      });
2f32cac 63
  }, [id]);
2f32cac 64
  return {
2f32cac 65
    user,
2f32cac 66
    loading,
2f32cac 67
    error,
2f32cac 68
  };
2f32cac 69
};
2f32cac 70
```
2f32cac 71
2f32cac 72
> After SWR
2f32cac 73
2f32cac 74
```tsx
2f32cac 75
import useSWR from "swr";
2f32cac 76
2f32cac 77
const fetcher = (...args) => fetch(...args).then((res) => res.json());
2f32cac 78
2f32cac 79
const useUser = (id: string) => {
2f32cac 80
  const { data, error, isLoading } = useSWR(`/users/${id}`, fetcher);
2f32cac 81
  return {
2f32cac 82
    user: data,
2f32cac 83
    isLoading,
2f32cac 84
    error: error,
2f32cac 85
  };
2f32cac 86
};
2f32cac 87
```
2f32cac 88
2f32cac 89
### Configuration
2f32cac 90
2f32cac 91
You can configure a global fetcher function so that you don't need pass the fetcher on every hook call using the `SWRConfig` Provider at the root app level. The library uses a global cache to store and share data across all components, you can also customise this behaviour with the `provider` option.
2f32cac 92
2f32cac 93
```tsx
2f32cac 94
import { SWRConfig } from "swr";
2f32cac 95
2f32cac 96
const fetcher = (...args) => fetch(...args).then((res) => res.json());
2f32cac 97
2f32cac 98
function App() {
2f32cac 99
  return (
2f32cac 100
    <SWRConfig value={{ fetcher: fetcher, provider: () => new Map() }}>
2f32cac 101
      <Page />
2f32cac 102
    </SWRConfig>
2f32cac 103
  );
2f32cac 104
}
2f32cac 105
```
2f32cac 106
2f32cac 107
### Automatic Revalidation
2f32cac 108
2f32cac 109
You can use the options parameter in the API to configure automatic revalidation of your components based on different criteria. This can be done at a global level using SWRConfig provider or at a local hook level using the options parameter.
2f32cac 110
2f32cac 111
- `revalidateIfStale`: automatically revalidate even if there is stale data
2f32cac 112
- `revalidateOnMount`: enable or disable automatic revalidation when component is mounted
2f32cac 113
- `revalidateOnFocus`: automatically revalidate when window gets focused
2f32cac 114
- `revalidateOnReconnect`: automatically revalidate when the browser regains a network connection
2f32cac 115
- `refreshInterval`:  automatically revalidate every interval in milliseconds
2f32cac 116
2f32cac 117
There are many more options apart from these.
2f32cac 118
2f32cac 119
### Manual Revalidation
2f32cac 120
2f32cac 121
There are 2 ways to trigger a revalidation request manually,
2f32cac 122
2f32cac 123
**1.** You can use the **mutate** function returned by the **useSWR** hook to trigger a revalidation of the data
2f32cac 124
2f32cac 125
```tsx
2f32cac 126
import useSWR from "swr";
2f32cac 127
2f32cac 128
const Profile = () => {
2f32cac 129
  const { data, error, isLoading, mutate } = useSWR(`/users/1`);
2f32cac 130
  if (error) return <div>failed to load</div>;
2f32cac 131
  if (isLoading) return <div className="text">loading...</div>;
2f32cac 132
  return (
2f32cac 133
    <div>
2f32cac 134
      <div>{JSON.stringify(data, null, 2)}</div>
2f32cac 135
      <button onClick={() => mutate()}>Update User</button>
2f32cac 136
    </div>
2f32cac 137
  );
2f32cac 138
};
2f32cac 139
```
2f32cac 140
2f32cac 141
This can be used to implement optimistic updates as well if you know what data needs to change and once the revalidation is complete the cache gets updated with new data from the server.
2f32cac 142
2f32cac 143
```tsx
2f32cac 144
mutate({ ...data, name: "John Doe" });
2f32cac 145
```
2f32cac 146
2f32cac 147
**2.** If you need to update the cache from another component which doesn't have access to the **useSWR** hook you can use the **mutate** function returned by the **useSWRConfig** to get access to the cache. Here you would need to provide the key to trigger a revalidation of the request.
2f32cac 148
2f32cac 149
```tsx
2f32cac 150
import { useSWRConfig } from "swr";
2f32cac 151
// or import { mutate } from "swr"
2f32cac 152
2f32cac 153
const UpdateButton = () => {
2f32cac 154
  const { mutate } = useSWRConfig();
2f32cac 155
  return (
2f32cac 156
    <div>
2f32cac 157
      <button onClick={() => mutate(`/users/1`)}>Update User</button>
2f32cac 158
    </div>
2f32cac 159
  );
2f32cac 160
};
2f32cac 161
```
2f32cac 162
2f32cac 163
Here as well you can do optimistic updates similarly,
2f32cac 164
2f32cac 165
```tsx
2f32cac 166
mutate(`/users/1`, { ...data, name: "John Doe" });
2f32cac 167
```
2f32cac 168
2f32cac 169
### **useSWRMutation**
2f32cac 170
2f32cac 171
This hook makes it easier to handle update requests and provides necessary state
2f32cac 172
2f32cac 173
```tsx
2f32cac 174
import useSWRMutation from "swr/mutation";
2f32cac 175
2f32cac 176
async function updateUser(url, data) {
2f32cac 177
  await fetch(url, {
2f32cac 178
    method: "POST",
2f32cac 179
    body: JSON.stringify(data),
2f32cac 180
  });
2f32cac 181
}
2f32cac 182
2f32cac 183
function Profile() {
2f32cac 184
  const { data, error, isMutating, trigger } = useSWRMutation(
2f32cac 185
    "/api/user/update",
2f32cac 186
    updateUser,
2f32cac 187
    options,
2f32cac 188
  );
2f32cac 189
  return (
2f32cac 190
    <button onClick={() => trigger({ name: "John Doe" })}>
2f32cac 191
      {isMutating ? "Updating..." : "Update User"}
2f32cac 192
    </button>
2f32cac 193
  );
2f32cac 194
}
2f32cac 195
```
2f32cac 196
2f32cac 197
**Parameters**
2f32cac 198
2f32cac 199
- `key`: a unique key string for the request
2f32cac 200
- `fetcher(key, { arg })`: an async function for remote mutation
2f32cac 201
- `options`: an optional object to configure revalidation and optimistic updates
2f32cac 202
2f32cac 203
**Returns**
2f32cac 204
2f32cac 205
- `data`: data for the given key returned from the update request
2f32cac 206
- `error`: error thrown by the request
2f32cac 207
- `trigger(arg, options)`: a function to trigger a remote mutation
2f32cac 208
- `reset`: a function to reset the state
2f32cac 209
- `isMutating`: if there's an ongoing update request