还在用axios发送请求?来看看alova的高阶用法!alova 提供了基础的,与 axios 相似的基础请求能力,你可
0. 什么是alova
alova 提供了基础的,与 axios 相似的基础请求能力,你可以配合 axios、fetch 等任何请求库使用,获得
响应缓存
、请求共享
、跨组件刷新
等开箱即用的特性
注意 本文档内容是以alova@2.x为基础进行介绍,目前alova@3.x版本已经发布,如果你打算使用新版本的话,请注意二者 之间的API差异
1.缓存策略
alova会按照请求的路径、参数、method等自动创建缓存key,然后对请求数据进行缓存,加快接口的响应,同时避免不必要的接口请求,降低对服务端的压力。 alova提供3种不同的缓存策略:
1.1 内存模式
内存缓存模式
是将响应数据存放在内存中,缓存在刷新页面即失效。
export const queryStudentDetail = (id) =>
alovaInst.Get(`/student/${id}`, {
// set the timestamp of memery cache
localCache: 10 * 60 * 60,
});
localCache默认为内存模式,因此我们只需要设置缓存时间即可。
1.2 占位模式
缓存占位模式
是将响应数据持久化,它将在刷新页面后立即更新到 data state 中作为占位数据,同时发送请求,开发者可以在响应前使用占位数据替代 Loading 状态。
export const queryRandom = () =>
alovaInst.Get('/query-random', {
localCache: {
mode: 'placeholder',
expire: 10 * 60 * 60,
},
});
占位模式会优先返回本地缓存的数据,同时在发起请求,获得响应数据后进行替换。这种模式可以让用户先看到数据,比起看loading状态的体验好得多。
1.3 恢复模式
export const queryRandom = () =>
alovaInst.Get('/query-random', {
localCache: {
mode: 'restore',
expire: 10 * 60 * 60,
},
});
缓存恢复模式
是将响应数据持久化,当请求命中缓存时将持久化缓存数据返回,不再发出请求。它一般用于一些需要服务端管理,但在一定时间内不变的数据。
恢复模式常用于一些数据变化很少变化或基本上不会变化的数据,例如节假日数据、城市数据等一些基础数据。
特别注意,这里的expire
除了可以设置为一个相对时间以外,也可以设置为一个绝对时间Date类型,例如我们假设今年的节假日数据在1月1日之前都不变化,则可以将expire设置为new Date('2025-01-01 00:00:00')
那万一我的数据就是发生了变化,然后又被前端给使用恢复模式缓存了,应该如何处理,这种情况我们可以给alova的方法增加一个tag属性,来标识缓存key值,从而让已缓存的数据失效,重新从接口获取。
export const queryHolidays = () =>
alovaInst.Get('/query-holidays', {
localCache: {
mode: 'restore',
expire: 10 * 60 * 60,
tag: 'v1.1'
},
});
2.当成store来用
了解了alova的缓存模式以后,对于一些页面组件间的共享数据来说,你就可以把alova当成一个微型的store来使用:
import { queryHolidays } from './api.js';
import { useRequest } from 'alova';
const {
loading,
error,
data: holidays,
} = useRequest(queryHolidays);
虽然这看起来并没有什么特别之处,但是却极大的减少了开发时对于store和hooks的依赖。
想想,如果按照常规的做法,你需要先创建一个store,可能还需要定义一些对应的getters/actions,或者创建一个hooks来对数据的缓存进行维护。而且类似的数据越来越多的时候,你就会发现,你的这些store或者hooks的功能都十分的雷同,无法就是查询缓存,请求接口,设置缓存,格式化数据...现在这些都可以被alova给完成了。
3.加载更多
使用分页策略,实现更加高性能易用的分页功能,分页相关状态自动管理、前后一页预加载、自动维护数据的新增/编辑/替换/移除,以及请求级的防抖功能。
- 初始化完成后会预加载下一页数据,下拉翻页无需等待;
- 添加、删除、修改列表项无需重置列表,它将自动处理成和重新请求一致的效果;
import { queryStudents } from "./api.js";
import { usePagination } from "@alova/scene-vue";
const {
loading,
data: students,
isLastPage,
page,
pageSize,
remove,
insert,
refresh,
reload,
update,
replace,
} = usePagination(
(page, pageSize) =>
queryStudents(page, pageSize, studentName.value || "", clsName.value || ""),
{
watchingStates: [studentName, clsName],
append: true,
initialData: [],
data: r => r,
debounce: [500],
}
);
usePagination一旦将append
设置为true
之后,将会变身为加载更多的模式,同时它还提供了完整一套关于加载更多列表的操作:
- 返回了
data
、loading
、isLastPage
、isLastPage
、refresh
、reload
等属性和方法,直接配置一个加载更多的UI组件,我们很快就能完成一个加载更多的列表开发 - 对于
isLastPage
的计算,pageCount 有值时会通过 pageCount 和 page 对比得到,否则会通过列表数据长度是否少于 pagSize 得到 - 对于列表数据提供了完整的
insert
、remove
、update
、replace
操作,借助这些方法,我们可以直接在列表上完成对数据的CRUD操作; - 借助
watchingStates
属性配置,可以完成对字段的变化监听,然后自动发起请求,因此我们可以完成列表过滤、搜索、筛选等常规功能;watchingStates
默认监听了page
和pageSize
属性,对于用作分页数据查询也十分有效; preloadPreviousPage
和preloadNextPage
默认自动加载当前页的相邻页数据,加快在切换分页或加载更多时数据的响应。
4.缓存自动失效方案
在上面,我们已经见识了alova强大的缓存策略和加载更多方案,但是同时也会带来一个问题:
如何主动让缓存失效
方法1:使用alova的invalidateCache
手动将单个方法或者全部缓存失效
方法2:自动失效
:对于一些关联性特别明显的接口,这个方法这个简洁,也更加符合接口整体逻辑的设计。例如我们有一个todo列表接口,有一个发布todo的接口,很明显,我发布todo以后,列表的本地缓存就应该失效,重新获取,否则用户就需要一直等待直到失效时间到期。
const getTodos = () => {
alova.Get('/todos', {
// 匹配method实例名称为submitTodo的失效源
hitSource: 'submitTodo'
});
}
const submitTodo = (data) => {
alova.Post('/todo', data, {
name: 'submitTodo'
});
}
我们定义了两个alova接口,一个获取todo列表,一个提交todo,当submitTodo提交成功后,将自动触发getTodos的缓存失效
,再次请求时将从服务端获取数据。
5.跨组件触发请求
从前,在一个组件中想要触发另一个组件中的请求,你需要将数据保存到 Store 中,通过分发 Action 完成。现在,你可以使用这个中间件消除组件层级的限制,在任意组件中快速地触发任意请求的操作函数。
例如,你可以某个组件中更新了菜单数据后,重新触发侧边菜单栏的重新请求,从而刷新数据。当操作了列表数据后,触发列表更新。
组件A:使用actionDelegationMiddleware进行委托操作:
import { actionDelegationMiddleware } from '@alova/scene-vue';
useRequest(queryTodo, {
middleware: actionDelegationMiddleware('actionName')
});
完成委托后,在其他任意组件中,我们可以通过accessAction
传入指定的委托名称触发组件 A 中的useRequest
的操作函数
import { accessAction } from '@alova/scene-vue';
accessAction('actionName', delegatedActions => {
// 调用组件A中的send函数
delegatedActions.send();
// 调用组件A中的abort函数
delegatedActions.abort();
});
至此,我们就摆脱store或组件层层传递的困扰,轻松完成跨组件的请求触发。
转载自:https://juejin.cn/post/7399954302217093156