1. SWR + Fetch API
使用了泛型,这样data, error就都有类型了,这个类型是使用时候传入的type
src/hooks/useFetch.ts
import useSWR from 'swr';
const fetcher = async (url: string) => {
const response = await fetch(url)
const data = response.json()
return data
}
// 和上面async写法一样的,这种是promise写法。两种方法返回的都是Promise
// const fetcher = (url: string) => fetch(url).then(res => res.json())
export default function useFetch<Data = any, Error = any>(url: string) {
const { data, error } = useSWR<Data, Error>(url, async (url) => {
const response = await fetch(url);
const data = response.json();
return data;
});
// const { data, error } = useSWR<Data, Error>(url, fetcher)
return { data, error };
}
使用
/pages/UserList.tsx
import useFetch from '../hooks/useFetch';
interface User {
id: number;
name: string;
}
const UserList: React.FC = () => {
const { data } = useFetch<User[]>('http://localhost:3333/users');
if (!data) {
return <p>加载中...</p>;
}
...
}
2. SWR + Axios
src/services/api.ts
import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:3333',
});
export default api;
src/hooks/useFetch.ts**
import useSWR from 'swr';
import api from '../services/api';
export default function useFetch<Data = any, Error = any>(url: string) {
const { data, error } = useSWR<Data, Error>(url, async (url) => {
const response = await api.get(url);
return response.data;
});
return { data, error };
}
使用 /pages/UserDetail.tsx
import React from 'react';
import { useParams } from 'react-router-dom';
import useFetch from '../hooks/useFetch';
interface User {
id: number;
name: string;
}
const UserDetails: React.FC = () => {
const { id } = useParams();
const { data } = useFetch<User>(`users/${id}`);
if (!data) {
return <p>Carregando...</p>;
}
...
}
3. 修改缓存中的数据
- data 是所有用户们的信息
- mutate() 改变缓存data中那个要改变的用户的信息
- 为什么这样做呢?因为第一次请求了所有用户的数据后,swr会做缓存,我们改变了某个用户的信息,直接更新缓存即可,不需要再请求一次拿所有用户的信息。那么你会想我改变了缓存中的数据,远程的数据不更新吗?其实是这样的,改变缓存中的数据能让我们更快的渲染数据到页面上(对于用户,他们只需要快速的页面数据变化感知,不关心你是否更新后端数据库),然后我们在背后做更新数据库的操作!!【见官方例子】
- 但是仅仅这样写有个问题,就是当我们改变用户列表中某个用户的名字时,然后立马点击进入该用户详情页时,发现显示的还是改变前的名字,过了1s(大概..)后才变成改变后的名字,那么如何解决这个问题呢?
- mutateGlobal(
users/${id}
, { id, name: ‘hahahah’ }) 加上这个
/pages/UserList.tsx
import React, { useCallback } from 'react';
import { Link } from 'react-router-dom';
import useFetch from '../hooks/useFetch';
import api from '../services/api';
interface User {
id: number;
name: string;
}
const UserList: React.FC = () => {
// 所有的用户数据
const { data, mutate } = useFetch<User[]>('users');
// 单个用户数据改变名字
const handleNameChange = useCallback(
(id: number) => {
api.put(`users/${id}`, { name: 'Chenxii' });
const updatedUsers = data?.map((user) => {
if (user.id === id) {
return { ...user, name: 'haha' };
}
return user;
});
// 更新缓存data里的那个需要改变的用户信息
mutate(updatedUsers, false);
},
[data, mutate]
);
...
}
再修改
import React, { useCallback } from 'react';
import { Link } from 'react-router-dom';
import { mutate as mutateGlobal } from 'swr';
import useFetch from '../hooks/useFetch';
import api from '../services/api';
interface User {
id: number;
name: string;
}
const UserList: React.FC = () => {
const { data, mutate } = useFetch<User[]>('users');
const handleNameChange = useCallback(
(id: number) => {
api.put(`users/${id}`, { name: 'Chenxii' });
const updatedUsers = data?.map((user) => {
if (user.id === id) {
return { ...user, name: 'haha' };
}
return user;
});
mutate(updatedUsers, false);
mutateGlobal(`users/${id}`, { id, name: 'hahaha' });
},
[data, mutate]
);
...
}
mutate 官方例子
import useSWR, { mutate } from 'swr'
function Profile () {
const { data } = useSWR('/api/user', fetcher)
return (
<div>
<h1>My name is {data.name}.</h1>
<button onClick={async () => {
const newName = data.name.toUpperCase()
// update the local data immediately, but disable the revalidation
mutate('/api/user', { ...data, name: newName }, false)
// 背后做的操作(用户不在意的)
// send a request to the API to update the source
await requestUpdateUsername(newName)
// 把更新后的数据库数据 再请求过来 更新本地的缓存(缓存和远程数据库同步)
// trigger a revalidation (refetch) to make sure our local data is correct
mutate('/api/user')
}}>Uppercase my name!</button>
</div>
)
}