@Tanstack/vue-query 的使用介绍

@Tanstack/vue-query 的使用介绍

前言

在今年的vue conf 会议上,提到了vue-query这个库,这里对它的基本使用做一个介绍。

会议资料地址: https://vueconf.cn/

Tanstack-query的前身是react-query,是一个本地的服务端状态管理的库,常和“乐观更新”配合使用。它会在本地维护一个基于内存的全局状态管理,当缓存中有数据的时候,优先使用缓存数据来展示,可以让用户获得非常流畅的体验(前提是网络状态正常,如果网络很差,可能长时间显示错误的数据)。同时后台请求数据,来保证数据的正确性。

tanstack-query的优势:

https://tanstack.com/query/latest/docs/framework/vue/typescript

  • 专用的devtools
  • 自动缓存请求过的数据
  • 自动后台查询
  • 窗口聚焦自动重新获取
  • 轮询/实时查询
  • 并行查询
  • 关联查询
  • 支持mutation API
  • 分页查询
  • 无限滚动
  • 请求取消
  • 自动垃圾回收
  • 错误重试
  • 数据预取
  • 支持初始化数据和占位数据
  • 自动网络监控
  • SSR 支持

简单的demo

可以从官网获取线上demo进行测试。

https://codesandbox.io/s/github/tanstack/query/tree/main/examples/vue/basic?from-embed=&file=/src/App.vue

🎯 线上demo热更新响应速度比较慢,而且不可以post更改数据。

可以使用本地启动demo项目,增加了json-server,因此可以使用restful风格的api实现增删改查的功能。

demo地址:https://github.com/hekang456/vue-query-example

如果需要使用json-server发其他请求,参考https://github.com/typicode/json-server

使用方式

这里使用最简单的代码覆盖最常见的使用场景,其他场景见文档。

1、获取数据

使用useQuery获取数据,需要设置queryKeyqueryFnqueryKey只要是可以序列化的数组即可,但需要保证全局唯一;queryFn是一个返回Promise的函数。

import { useQuery } from '@tanstack/vue-query';const { isPending, isError, isFetching, data, error, refetch } = useQuery({queryKey: ['posts'],queryFn: fetchPostsApi
});

在这里插入图片描述

当页面打开的时候,自动请求了 ["posts"]接口,注意看 devtools 中数据的状态,从 Fetching (获取中)变成了 Stale(已过期)。

这是默认的配置,数据获取之后立刻变成“已过期”,这样当触发了一些条件的时候就会立马重新请求,比如页面聚焦、页面重新变成活跃状态等。

2、页面聚焦/页面重新变成活跃重新请求数据

这里以页面重新变成活跃为例。

在这里插入图片描述

Posts.vue页面,切换到Post.vue页面,可以看到请求了 ["post", "1"]的数据, ["post", "1"] 也是从 Fetching 变成了 Stale,而["posts"]数据状态变成了inactive(非活跃)。

当点击back回到Posts.vue页面的时候,立刻展示了缓存中的数据,同时 ["posts"]对应的接口立马重新请求后端。因为数据没有变化,所以页面也没有改变,提供了流畅的体验。

3、自动缓存

我们以第一条数据为例

在这里插入图片描述

当数据请求过之后,就会缓存起来,当再次显示时,会直接展示缓存中的数据,同时取请求后端数据。如果数据没有变化,页面也没有改变;否则修改页面。

4、修改过期时间

默认情况下,数据请求后会立刻获取,但是某些数据,开发者明确知道它很长时间都不会更新,这时候就可以设置过期时间。

这里单独修改["posts"]的过期时间.

const { isPending, isError, isFetching, data, error, refetch } = useQuery({queryKey: ['posts'],queryFn: fetchPostsApi,// 一小时staleTime: 10 * 60 * 1000,
});

在这里插入图片描述

可以看到,["posts"]数据不再会立刻过期,哪怕页面重新变成活跃状态,也只是使用缓存数据渲染,而没有请求新的数据。

5、手动刷新

调用refresh方法,来手动刷新接口,这里以["posts"]接口为例。

Posts.vue文件中,增加一个按钮,调用uesQuery返回的refresh方法。

<button @click="refetch">refresh Posts</button>

在这里插入图片描述

每次调用refresh,都会发送一个新的请求,即使数据还是Fresh状态。

6、数据轮询

增加refetchInterval属性。如果配合enable属性,可以方便的控制轮询暂停和继续。见 9。

const { isPending, isError, isFetching, data, error, refetch } = useQuery({queryKey: ['posts'],queryFn: fetchPostsApi,staleTime: 10 * 60 * 1000,// 2s轮询一次接口refetchInterval: 2 * 1000
});

在这里插入图片描述

这是一个非常实用的功能,避免了手写轮询带来的复杂代码逻辑。

7、自动重试

如果接口报错,默认会自动重试,但是只在get接口生效。这是为了防止其他类型的请求会多次修改后端数据。

因为前端报错的原因是多种的,比如后端处理时间太长,导致前端超时报错。但只要请求发到了后端,就会执行操作。

为了演示这种情况,需要让接口报错。我们改一下fetchPostsApi,让它报错。

export const fetchPostsApi = async (): Promise<Post[]> =>await fetch('http://localhost:3000/posts').then((response) => {// return response.json();throw new Error('error');});

在这里插入图片描述

可以看到,如果接口报错,会默认重试三次,并且重试的间隔时间翻倍。在重试过程中,数据一致处于pending状态,最后变成了error状态。

8、数据预取

假设当数据移动到某一条post数据上时,用户大概率是会点击查看的。这时候可以对这条数据预取,用户点击时可以及时显示内容。

在每一条数据上都绑定一个mouseenter事件,实现这个功能需要queryClient来实现。

需要指定唯一的queryKey,这个keyPost.vue组件中的请求方法是一样的,所以二者可以共用一份缓存数据。

<script lang="ts" setup>
import { useQuery, useQueryClient } from '@tanstack/vue-query';
import { fetchPostsApi, fetchPostApi } from './fetch';// ......
const queryClient = useQueryClient();
const prefetchPost = async (id: number) => {await queryClient.prefetchQuery({queryKey: ['post', id],queryFn: () => fetchPostApi(id)});
};
</script><template><h1>Posts</h1>// ......<div v-else-if="data"><ul><li v-for="item in data" :key="item.id"><a@mouseenter="prefetchPost(item.id)"@click="$emit('setPostId', item.id)"href="#":class="{ visited: isVisited(item.id) }">{{ item.title }}</a></li></ul></div>
</template>

在这里插入图片描述

当打开详情时,数据是瞬间展示的,并没有loading的过程。

9、控制数据获取的时机

有时候我们不希望数据立刻获取,而是等到触发了某些条件的时候在获取。

比如,我们假设["post"]中的数据,不是进入页面就需要获取,而是一些条件满足后才可以请求。以一个变量为例。

<script>
const validate = ref(false)
const { isPending, isError, isFetching, data, error, refetch } = useQuery({queryKey: ['posts'],queryFn: fetchPostsApi,// 只有验证通过,才可以发请求enabled: validate,
});
</script><template>
<button @click="validate = true">validate</button>
</template>

在这里插入图片描述

开始时,请求处于disabled状态,没有发送,直到点击了按钮,请求才发出。

10、关联请求

依然是用enable属性来实现的,比如官方的例子中,只有userid属性,才去发出请求。

// Get the user
const { data: user } = useQuery({queryKey: ['user', email],queryFn: () => getUserByEmail(email.value),
})const userId = computed(() => user.value?.id)
const enabled = computed(() => !!user.value?.id)// Then get the user's projects
const { isIdle, data: projects } = useQuery({queryKey: ['projects', userId],queryFn: () => getProjectsByUser(userId.value),enabled, // The query will not execute until `enabled == true`
})

11、并行请求

多个请求之间,默认是并行的,比如:

const usersQuery = useQuery({ queryKey: ['users'], queryFn: fetchUsers })
const teamsQuery = useQuery({ queryKey: ['teams'], queryFn: fetchTeams })

同时,对于同一类请求,可以使用useQueries来并行请求。

const users = computed(...)
const queries = computed(() => users.value.map(user => {return {queryKey: ['user', user.id],queryFn: () => fetchUserById(user.id),}})
);
const userQueries = useQueries({queries: queries})

12、分页请求

需要修改App.vue文件,把分页组件显示出来。具体代码可以看代码仓库中的写法。

<Post v-if="postId > -1" :postId="postId" @setPostId="setPostId" />
<!-- <Posts v-else :isVisited="isVisited" @setPostId="setPostId" /> -->
<PagePosts v-else />

在这里插入图片描述

可以看到,请求下一页,在请求新接口的过程中,数据依然是使用上一页的,而没有展示loading。请求成功后进行替换。

而点击上一页,会直接用缓存数据渲染,同时后台发出请求,如果数据一致,页面UI不发生变化。

这是乐观更新的一种实现。

13、修改数据

修改数据的功能比较简单,我们给列表增加一个数据。

修改App.vue文件,增加以下代码,调用useMutation

插入数据成功后,手动让["post"]数据缓存失效,这样的话,这个接口会重新发送请求。exact: true意思是精确匹配,否则数组中包含posts的所有缓存都会失效

<script lang="ts" setup>import { addPostApi } from './fetch';
import { useMutation, useQueryClient } from '@tanstack/vue-query';const queryClient = useQueryClient();const { isLoading, mutate } = useMutation({mutationFn: addPostApi,onSuccess: () => {queryClient.invalidateQueries({ queryKey: ['posts'], exact: true });}
});const addPost = () => {mutate({userId: 1,id: Date.now(),title: 'bbbbbb',body: 'bbbbbb'});
};
</script><template><button @click="addPost">add one postId</button>
</template>

在这里插入图片描述

这里点击按钮后,发送了两个请求,第一个post请求,插入一条数据,第二个是onSuccess回调中让列表缓存失效,从而重新请求列表数据

🚀 从这里也可以看出来,App.vue文件中并没有Post.vue组件的数据,但是只要修改对应的queryKey,同样可以影响到Post.vue组件。这避免了数据逐级传递和父组件管理全部子组件数据带来的复杂度问题。

14、初始数据和占位数据

先看初始数据,initialData的数据被认为是有效的,可以存储在缓存中,为了显示效果,给它设置一个过期时间。

const { isPending, isError, isFetching, data, error, refetch } = useQuery({queryKey: ['posts'],queryFn: fetchPostsApi,staleTime: 1000 * 60,initialData: [{id: 10000,userId: 1,title: 'First Post',body: 'Hello World'}]
});

在这里插入图片描述

可以看到,数据不过期,就不会请求接口

再看一下占位数据的表现。

const { isPending, isError, isFetching, data, error, refetch } = useQuery({queryKey: ['posts'],queryFn: fetchPostsApi,staleTime: 1000 * 60,placeholderData: [{id: 10000,userId: 1,title: 'First Post',body: 'Hello World'}]
});

在这里插入图片描述

占位数据不会缓存到内存中,当真正的数据返回时,占位数据会被替换。

15、网络状态和数据状态

数据状态:

  • pending
  • success
  • error

网络状态:

  • fetching
  • paused
  • idle

🚁 数据状态和网络状态并不总是对应,数据状态对应的是缓存中的数据状态,网络状态对应的是当次网络请求。

举个例子:

1 假如["post"]接口对应的数据已经请求成功了,那么数据状态是success,网络状态是idle;如果这个请求被再次激活,数据状态依然是success,网络状态是fetching --> idle

2 假如数据状态是pending,这时候可能在网络请求过程中,网络状态是fetching,也可能网络中断,网络状态是paused

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/53036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3.6 逻辑运算

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

wpf prism 《3》 弹窗 IOC

传统的弹窗 这种耦合度高 new 窗体() . Show(); new 窗体() . ShowDialog(); 利用Prism 自动的 IOC 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 》》否…

【C语言】十六进制、二进制、字节、位、指针、数组

【C语言】十六进制、二进制、字节、位 文章目录 [TOC](文章目录) 前言一、十六进制、二进制、字节、位二、变量、指针、指针变量三、数组与指针四、指针自加运算五、二维数组与指针六、指向指针的指针七、指针变量作为函数形参八、函数指针九、函数指针数组十、参考文献总结 前…

系统功能性能优化:从问题定位到解决方案的系统性分析

引言 在现代软件系统中&#xff0c;性能优化是确保系统稳定、响应迅速和资源高效利用的关键。面对复杂的系统架构和业务逻辑&#xff0c;进行性能优化往往需要遵循一系列系统性的步骤&#xff0c;以确保问题被准确识别&#xff0c;解决方案被有效实施。以下是一套专业的系统功…

(四)Kafka离线安装 - Kafka下载及安装

Kafka官方下载地址&#xff1a;Apache Kafka 这时候下载安装版本。 我这里的安装目录在 /usr/local/ cd /usr/local/# 创建目录 mkdir kafka cd kafka mkdir kafka_log 把下载的压缩包&#xff0c;放入到/usr/local/kafka/目录下&#xff0c;解压。 # 解压 tar -zxvf kafka…

前端踩坑记录:javaScript复制对象和数组,不能简单地使用赋值运算

问题 如图&#xff0c;编辑table中某行的信息&#xff0c;发现在编辑框中修改名称的时候&#xff0c;表格中的信息同步更新。。。 检查原因 编辑页面打开时&#xff0c;需要读取选中行的信息&#xff0c;并在页面中回显。代码中直接将当前行的数据对象赋值给编辑框中的表单对…

[从0开始AIGC][LLM]:LLM中Encoder-Only or Decoder-Only?为什么主流LLM是Decoder-Only?

LLM中Encoder-Only or Decoder-Only & 为什么主流LLM是Decoder-Only&#xff1f; 文章目录 LLM中Encoder-Only or Decoder-Only & 为什么主流LLM是Decoder-Only&#xff1f;1. 什么是Encoder-only、Decoder-Only2. 为什么当前主流的LLM都是Decoder-only的架构低秩问题 …

秋招/春招投递公司记录表格

最近在准备秋招&#xff0c;在各个平台投递秋招简历&#xff0c;什么官网&#xff0c;邮箱&#xff0c;boss&#xff0c;应届生各个平台上&#xff0c;投递的平台比较多&#xff0c;比较乱&#xff0c;因此自己想将这些平台投递记录都收集到一个表格上&#xff0c;所以在腾讯文…

bladeX默认审批流flowable如何设置

下面就是流程图必须得写 ${taskUser} 你要配什么 就给审批流的service传什么

VSCode必备插件!快看过来!

同学同学&#xff0c;你是不是也很头疼VSCode不知道安装什么插件啊&#xff1f;尤其是萌新小白&#xff0c;更是一头雾水&#xff0c;那就快来一起看看吧~我帮你整理了一些非常实用的插件&#xff0c;安装上它们&#xff0c;你的开发体验会大大提升&#xff01; 1. Chinese (S…

Call openai-node in the backend or call https in the frontend?

题意&#xff1a;在后端调用 openai-node 还是在前端调用 https&#xff1f; 问题背景&#xff1a; I have a web application by ReactJS and Nodejs. This application calls OpenAI APIs. 我有一个使用 ReactJS 和 Node.js 开发的 Web 应用程序。这个应用程序调用 OpenAI …

零基础入门转录组数据分析——预后模型之lasso模型

零基础入门转录组数据分析——预后模型之lasso模型 目录 零基础入门转录组数据分析——预后模型之lasso模型1. 预后模型和lasso模型基础知识2. lasso预后模型&#xff08;Rstudio&#xff09;——代码实操2. 1 数据处理2. 2 构建lasso预后模型2. 3 提取Lasso预后基因2. 4 计算风…

Pyqt5高级技巧:多线程任务、窗体交互、常用控件介绍(含基础Demo)

目录 一、多线程任务和多窗体交互 二、增删改查Demo 三、UI设计 【css效果代码对照表】 【实现效果】 【实现代码】 【常见问题】 Q1&#xff1a;工具栏怎么加&#xff0c;资源图片怎么加 Q2&#xff1a;控件被背景染色怎么办&#xff1f; Q3&#xff1a;QTdesigner有…

LVS的加权轮询算法

http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling 加权轮循调度是为了更好地处理不同处理能力的服务器。每个服务器都可以被分配一个权重&#xff0c;一个表示处理能力的整数值。权值较高的服务器比权值较低的服务器首先接收到新连接&#xff0c;权值较…

<Rust>egui学习之小部件(七):如何在窗口中添加颜色选择器colorpicker部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第七篇博…

记一次学习--webshell绕过(利用清洗函数)

目录 样本 样本修改 样本 <?php $a array("t", "system"); shuffle($a); $a[0]($_POST[1]); 通过 shuffle 函数打乱数组,然后通过$a[0]取出第一个元素&#xff0c;打乱后第一个元素可能是t也可能是system。然后再进行POST传参进行命令执行。 这里抓…

部署Rancher2.9管理K8S1.26集群

文章目录 一、实验须知1、Rancher简介2、当前实验环境 二、部署Rancher1、服务器初始化操作2、部署Rancher3、登入Rancher平台 三、Rancher对接K8S集群四、通过Rancher仪表盘部署Nginx服务1、创建命名空间2、创建Deployment3、创建Service 一、实验须知 1、Rancher简介 中文官…

【自由能系列(中级),代码模拟】预测编码的核心:三个关键方程式的详解

预测编码的核心&#xff1a;三个关键方程式的详解 ——探索预测编码背后的数学原理与应用 核心结论&#xff1a;预测编码是一种基于贝叶斯定理的理论框架&#xff0c;它通过三个关键方程式描述了大脑如何处理和解释来自环境的信号。这些方程式分别建立了贝叶斯定理的简化形式、…

9月新机首发:骁龙芯片+超大电池,游戏玩家的终极选择

随着秋风送爽的9月到来&#xff0c;智能手机和电子设备市场也迎来了新一轮的热潮。8月份的新机发布热潮刚刚退去&#xff0c;9月份的新机已经迫不及待地揭开了神秘的面纱。在众多备受期待的产品中&#xff0c;红魔品牌抢先官宣&#xff0c;两款全新的游戏平板将在9月5日正式亮相…

论文速读|通过人类远程操作的深度模仿学习框架:人型机器人的行走操纵技能

项目地址&#xff1a;Deep Imitation Learning for Humanoid Loco-manipulation through Human Teleoperation 本文详细介绍了 TRILL&#xff08;Teleoperation and Imitation Learning for Loco-manipulation&#xff09;框架&#xff0c;它是一个用于人型机器人行走操纵技能训…