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 revalidationmutate('/api/user', { ...data, name: newName }, false)// 背后做的操作(用户不在意的)// send a request to the API to update the sourceawait requestUpdateUsername(newName)// 把更新后的数据库数据 再请求过来 更新本地的缓存(缓存和远程数据库同步)// trigger a revalidation (refetch) to make sure our local data is correctmutate('/api/user')}}>Uppercase my name!</button></div>)}
