1. SWR + Fetch API

使用了泛型,这样data, error就都有类型了,这个类型是使用时候传入的type

src/hooks/useFetch.ts

  1. import useSWR from 'swr';
  2. const fetcher = async (url: string) => {
  3. const response = await fetch(url)
  4. const data = response.json()
  5. return data
  6. }
  7. // 和上面async写法一样的,这种是promise写法。两种方法返回的都是Promise
  8. // const fetcher = (url: string) => fetch(url).then(res => res.json())
  9. export default function useFetch<Data = any, Error = any>(url: string) {
  10. const { data, error } = useSWR<Data, Error>(url, async (url) => {
  11. const response = await fetch(url);
  12. const data = response.json();
  13. return data;
  14. });
  15. // const { data, error } = useSWR<Data, Error>(url, fetcher)
  16. return { data, error };
  17. }

使用
/pages/UserList.tsx

  1. import useFetch from '../hooks/useFetch';
  2. interface User {
  3. id: number;
  4. name: string;
  5. }
  6. const UserList: React.FC = () => {
  7. const { data } = useFetch<User[]>('http://localhost:3333/users');
  8. if (!data) {
  9. return <p>加载中...</p>;
  10. }
  11. ...
  12. }

2. SWR + Axios

src/services/api.ts

  1. import axios from 'axios';
  2. const api = axios.create({
  3. baseURL: 'http://localhost:3333',
  4. });
  5. export default api;


src/hooks/useFetch.ts**

  1. import useSWR from 'swr';
  2. import api from '../services/api';
  3. export default function useFetch<Data = any, Error = any>(url: string) {
  4. const { data, error } = useSWR<Data, Error>(url, async (url) => {
  5. const response = await api.get(url);
  6. return response.data;
  7. });
  8. return { data, error };
  9. }

使用 /pages/UserDetail.tsx

  1. import React from 'react';
  2. import { useParams } from 'react-router-dom';
  3. import useFetch from '../hooks/useFetch';
  4. interface User {
  5. id: number;
  6. name: string;
  7. }
  8. const UserDetails: React.FC = () => {
  9. const { id } = useParams();
  10. const { data } = useFetch<User>(`users/${id}`);
  11. if (!data) {
  12. return <p>Carregando...</p>;
  13. }
  14. ...
  15. }

3. 修改缓存中的数据

  • data 是所有用户们的信息
  • mutate() 改变缓存data中那个要改变的用户的信息
  • 为什么这样做呢?因为第一次请求了所有用户的数据后,swr会做缓存,我们改变了某个用户的信息,直接更新缓存即可,不需要再请求一次拿所有用户的信息。那么你会想我改变了缓存中的数据,远程的数据不更新吗?其实是这样的,改变缓存中的数据能让我们更快的渲染数据到页面上(对于用户,他们只需要快速的页面数据变化感知,不关心你是否更新后端数据库),然后我们在背后做更新数据库的操作!!【见官方例子】
  • 但是仅仅这样写有个问题,就是当我们改变用户列表中某个用户的名字时,然后立马点击进入该用户详情页时,发现显示的还是改变前的名字,过了1s(大概..)后才变成改变后的名字,那么如何解决这个问题呢?
  • mutateGlobal(users/${id}, { id, name: ‘hahahah’ }) 加上这个

/pages/UserList.tsx

  1. import React, { useCallback } from 'react';
  2. import { Link } from 'react-router-dom';
  3. import useFetch from '../hooks/useFetch';
  4. import api from '../services/api';
  5. interface User {
  6. id: number;
  7. name: string;
  8. }
  9. const UserList: React.FC = () => {
  10. // 所有的用户数据
  11. const { data, mutate } = useFetch<User[]>('users');
  12. // 单个用户数据改变名字
  13. const handleNameChange = useCallback(
  14. (id: number) => {
  15. api.put(`users/${id}`, { name: 'Chenxii' });
  16. const updatedUsers = data?.map((user) => {
  17. if (user.id === id) {
  18. return { ...user, name: 'haha' };
  19. }
  20. return user;
  21. });
  22. // 更新缓存data里的那个需要改变的用户信息
  23. mutate(updatedUsers, false);
  24. },
  25. [data, mutate]
  26. );
  27. ...
  28. }

再修改

  1. import React, { useCallback } from 'react';
  2. import { Link } from 'react-router-dom';
  3. import { mutate as mutateGlobal } from 'swr';
  4. import useFetch from '../hooks/useFetch';
  5. import api from '../services/api';
  6. interface User {
  7. id: number;
  8. name: string;
  9. }
  10. const UserList: React.FC = () => {
  11. const { data, mutate } = useFetch<User[]>('users');
  12. const handleNameChange = useCallback(
  13. (id: number) => {
  14. api.put(`users/${id}`, { name: 'Chenxii' });
  15. const updatedUsers = data?.map((user) => {
  16. if (user.id === id) {
  17. return { ...user, name: 'haha' };
  18. }
  19. return user;
  20. });
  21. mutate(updatedUsers, false);
  22. mutateGlobal(`users/${id}`, { id, name: 'hahaha' });
  23. },
  24. [data, mutate]
  25. );
  26. ...
  27. }

mutate 官方例子

  1. import useSWR, { mutate } from 'swr'
  2. function Profile () {
  3. const { data } = useSWR('/api/user', fetcher)
  4. return (
  5. <div>
  6. <h1>My name is {data.name}.</h1>
  7. <button onClick={async () => {
  8. const newName = data.name.toUpperCase()
  9. // update the local data immediately, but disable the revalidation
  10. mutate('/api/user', { ...data, name: newName }, false)
  11. // 背后做的操作(用户不在意的)
  12. // send a request to the API to update the source
  13. await requestUpdateUsername(newName)
  14. // 把更新后的数据库数据 再请求过来 更新本地的缓存(缓存和远程数据库同步)
  15. // trigger a revalidation (refetch) to make sure our local data is correct
  16. mutate('/api/user')
  17. }}>Uppercase my name!</button>
  18. </div>
  19. )
  20. }