前端实现对请求的接口返回数据做缓存的最佳实践

951 阅读1分钟

需求背景

这个页面有些接口是反复调用了,针对已经请求过的,不要再像后端发送请求了,前端自己做缓存吧

分析

  1. 前端针对请求过的数据存在内存里面;
  2. 缓存在内存里的数据只是在当前页面有用,页面卸载时需要清除数据。

实现

方法1:在页面中使用Map缓存数据

import React, { useEffect, useState } from "react";
import axios from 'axios';
import { Button, Space, Spin, Table } from 'antd';
axios.defaults.baseURL = 'https://api.github.com';

const columns = [
  {
    title: '名称',
    dataIndex: 'name',
    key: 'name',
  }
]
// !定义在函数组件外,是需要在页面卸载的时候清除的,否则针对单页面再次进来是有影响的
const cacheMap = new Map();
const Demo = () => {
  const [loading, setLoading] = useState<boolean>(false);
  const [list, setList] = useState<Array<any>>([])
  
  const fetchList = async (username :string) => {
    setLoading(true);
    // 实现缓存
    // 键值:这里用得是请求的参数,因为参数这里能保证是唯一的
    const cacheResult = cacheMap.get(username)
    // 有了,就直接拿来用
    if (cacheResult) {
      setList(cacheResult)
      setLoading(false);
      return
    }
    const res: any = await axios.request({
      url: `users/${username}/repos`,
      method: 'get'
    })
    // 不存在在缓存中,就存一份
    cacheMap.set(username, res.data);
    setLoading(false);
    setList(res.data);
  }

  const getUserInfo = (username: string) => {
    fetchList(username)
  }
  useEffect(() => {
    return () => {
      // 卸载
      cacheMap.clear();
    }
  }, [])
  return (
    <Spin spinning={loading}>
      <Space size="small">
        <Button onClick={() => getUserInfo('Believel')}>Believle</Button>
        <Button onClick={() => getUserInfo('zhangxiang958')}>zhangxiang958</Button>
        <Button onClick={() => getUserInfo('tanggd')}>tanggd</Button>
        <Button onClick={() => getUserInfo('baozouai')}>baozouai</Button>
      </Space>
      <Table dataSource={list} columns={columns} rowKey='id' />
    </Spin>
  )
};
export default Demo;

这种方式是直接写在业务代码中的,而且if(cacheResult)内的处理逻辑,与外面有些逻辑是重复的

方法2:从业务代码中抽离出来,缓存请求接口

  1. cacheService.ts
import axios from 'axios'

export interface CacheServiceState {
  store: any;
}

class CacheService {
  store: any;
  constructor() {
    this.store = {};
  }
  async fetch(params: any) {
    // 最好保证请求参数每次是唯一的,否则的话不适用这种缓存键
    const fetchCacheKey = JSON.stringify(params);
    if (this.store[fetchCacheKey]) {
      return this.store[fetchCacheKey]
    }
    const result = await axios.request(params);
    this.store[fetchCacheKey] = result;
    return result;
  }
  clearCache() {
    this.store = {};
  }
}
const CacheServiceInstance = new CacheService();
export default CacheServiceInstance;
  1. demo.tsx
import React, { useEffect, useState } from "react";
import axios from 'axios';
import { Button, Space, Spin, Table } from 'antd';
axios.defaults.baseURL = 'https://api.github.com';
import CacheServiceInstance from './cacheService';

const columns = [
  {
    title: '名称',
    dataIndex: 'name',
    key: 'name',
  }
]
const Demo = () => {
  const [loading, setLoading] = useState<boolean>(false);
  const [list, setList] = useState<Array<any>>([])
  const fetchList = async (username :string) => {
    setLoading(true);
    const res: any = await CacheServiceInstance.fetch({
      url: `users/${username}/repos`,
      method: 'get'
    })
    setLoading(false);
    setList(res.data);
  }

  const getUserInfo = (username: string) => {
    fetchList(username)
  }
  useEffect(() => {
    return () => {
        // 清除缓存
        CacheServiceInstance.clearCache();
    }
  }, [])
  return (
    <Spin spinning={loading}>
      <Space size="small">
        <Button onClick={() => getUserInfo('Believel')}>Believle</Button>
        <Button onClick={() => getUserInfo('zhangxiang958')}>zhangxiang958</Button>
        <Button onClick={() => getUserInfo('tanggd')}>tanggd</Button>
        <Button onClick={() => getUserInfo('baozouai')}>baozouai</Button>
      </Space>
      <Table dataSource={list} columns={columns} rowKey='id' />
    </Spin>
  )
};
export default Demo;

实现与业务代码分离,降低代码耦合度

总结

coding时多思考,少抱怨,加油!