使用SWR Hooks在Vue3中实现高效的数据加载和缓存(完整案例)

最终在IDB上的成品效果
使用SWR Hooks在Vue3中实现高效的数据加载和缓存(完整案例)

前言

每次都说把Api介绍一遍有什么?这次我送你们一个完整的可运行的代码案例。各位自取

在第一次通过网络获取之后,在时间范围内从本地读取,不再请求网络。各位可以试试

现在来实现一个类似的SWR的Vue自定义hooks,使用axios作为数据获取工具、idb作为本地缓存工具

安装依赖:

npm install axios idb-keyval 

接下来,我们可以创建一个名为 useSWR.js 的hooks,该hooks将接收三个参数:

  1. key:用于区分不同数据的关键字。
  2. fetcher:用于获取数据的函数。
  3. options:用于配置SWR行为的选项对象。

自定义hooks useSWR.js

import { reactive, toRefs, watchEffect } from 'vue'  // 引入 Vue3 响应式数据工具包
import { get as idbGet, set as idbSet } from 'idb-keyval'  // 引入 IndexedDB 操作库

const defaultOptions = {
  refreshInterval: 0,  // 缓存刷新的时间间隔,默认不自动刷新
  ttl: Infinity  // 缓存的有效时间,默认为永久有效
}

// 定义一个 useSWR 函数,接收三个参数
export default function useSWR(key, fetcher, options = {}) {
  // 使用 reactive 函数创建响应式数据对象
  const state = reactive({
    data: null,  // 存储返回的数据
    error: null,  // 存储请求发生的错误
    isLoading: false  // 是否正在请求数据
  })

  // 合并默认选项和传入的选项
  const { refreshInterval, ttl } = Object.assign({}, defaultOptions, options)

  // 定义一个 fetch 函数,用于获取数据
  async function fetch() {
    state.isLoading = true  // 数据正在加载中,设置 isLoading 属性为 true
    try {
      // 调用 fetcher 函数获取数据
      const data = await fetcher()
      state.data = data  // 将获取到的数据存储在 data 属性中
      state.error = null  // 请求成功,将 error 属性设置为 null
      state.isLoading = false  // 数据请求成功,设置 isLoading 属性为 false
      idbSet(key, { data, timestamp: Date.now() })  // 将获取到的数据存储在 IndexedDB 数据库中
    } catch (error) {
      state.error = error  // 请求发生错误,将 error 属性设置为错误信息
      state.isLoading = false  // 数据请求失败,设置 isLoading 属性为 false
    }
  }

  // 定义一个 fetchIfNeeded 函数,用于检查是否需要重新获取数据
  async function fetchIfNeeded() {
    // 从 IndexedDB 中获取缓存数据
    const cachedData = await idbGet(key)
    // 如果存在缓存数据,并且缓存未过期,则直接使用缓存数据
    if (cachedData && (Date.now() - cachedData.timestamp < ttl)) {
      state.data = cachedData.data
      return
    }
    // 如果不存在缓存数据或者缓存已过期,则重新获取数据
    await fetch()
  }

  // 使用 watchEffect 监听 state 数据对象的变化
  watchEffect(() => {
    fetchIfNeeded()  // 执行 fetchIfNeeded 函数,检查是否需要重新获取数据
    // 如果设置了缓存刷新时间,则使用 setInterval 定时器自动刷新缓存
    if (refreshInterval > 0) {
      const intervalId = setInterval(fetchIfNeeded, refreshInterval)
      // 返回一个函数,用于在组件销毁前清除定时器
      return () => clearInterval(intervalId)
    }
  })

  // 使用 toRefs 函数响应
  return toRefs(state)
}

代码解释

导入了Vue3的一些API,以及idb-keyval。

然后,我们定义了一些默认选项,用于在options参数未提供时使用。

接下来,我们定义了一个名为 useSWR 的函数,该函数接收三个参数。在函数内部,我们首先创建了一个响应式的 state 对象,其中包含了 dataerrorisLoading 三个属性。

然后,我们解构出 refreshIntervalttl 选项,并为它们提供了默认值。接下来,我们定义了一个名为 fetch 的函数,该函数用于获取数据,并将结果保存到IDB中。

fetchIfNeeded 函数中,我们首先从IDB中获取缓存的数据。如果缓存的数据存在且没有过期,则直接将其设置为state.data。否则,我们将调用 fetch 函数来获取最新的数据。

watchEffect 中,我们首先调用 fetchIfNeeded 函数来尝试从缓存中获取数据。然后,如果 refreshInterval 大于0,我们使用 setInterval函数来定期调用 fetchIfNeeded函数以更新数据。最后,我们返回一个通过toRefs函数转换后的state` 对象,以便在Vue3中可以直接访问其属性。

现在,我们可以使用 useSWR hooks 来获取和显示数据。下面是一个例子:

使用案例

<template>
  <div>
    <div v-if="isLoading">Loading...</div>
    <div v-if="error">Error: {{ error.message }}</div>
    <ul v-if="data">
      <li v-for="item in data" :key="item.id">{{ item.title }}</li>
    </ul>
  </div>
</template>

<script>
import { defineComponent } from 'vue'
import useSWR from './useSWR'
import axios from 'axios'


export default defineComponent({
  setup() {
    const { data, error, isLoading } = useSWR(
      'todos',
      async () => {
        const response = await axios.get('https://jsonplaceholder.typicode.com/todos')
        return response.data
      },
      { refreshInterval: 5000 }
    )

    return { data, error, isLoading }
  }
})
</script>

总结

在这个例子中,我们使用 useSWR hooks 来获取名为 ‘todos’ 的数据,并将其显示为一个无序列表。我们传递了一个 fetcher 函数来获取数据,该函数将从远程API获取数据。我们还传递了一个 options 对象来配置SWR行为,例如定期更新数据的间隔时间。

最后,我们使用Vue3的 defineComponent 函数来定义一个Vue组件,然后将 useSWR hooks 返回的数据绑定到模板中的相应元素上。

这就是使用axios、idb-keyval和Vue3实现完整的SWR的hooks的步骤。SWR使我们能够在减少网络请求次数的同时,保持UI的及时更新。通过使用本地缓存,我们可以减少网络请求,而使用Vue3的响应式系统则使我们能够实时更新UI。

原文链接:https://juejin.cn/post/7227715728362651709 作者:布衣1983

(2)
上一篇 2023年5月1日 上午10:46
下一篇 2023年5月1日 上午10:57

相关推荐

发表回复

登录后才能评论