懒人版请求库alovajs教程4:使用useHook发送请求

alova是一个轻量级的请求策略库,旨在简化接口的管理和使用。它分为两部分:

  1. 声明式实现复杂请求: 支持开发者使用声明式方法实现复杂请求,如请求共享、分页请求、表单提交、断点续传等,无需编写大量代码,提高开发效率,应用性能,减轻服务端压力。

  2. API自动管理和维护: 可生成完整的、描述详尽的请求函数的TypeScript类型,使前端项目与服务器端无缝对接,无需查阅API文档,获得类型提示。当服务端API更新时,前端项目会收到通知并阻止项目发布。

使用alovajs后,你只需要选择对应的useHook进行请求即可,被称为懒人版请求库。如果你也喜欢 alovajs,请在Github 仓库中贡献一颗 star,这对我们非常重要。

欢迎加入交流社区

有任何使用问题,你可以加入以下群聊咨询,也可以在github 仓库中发布 Discussions,如果遇到问题,也请在github 的 issues中提交,我们会在最快的时间解决。

同时也欢迎贡献你的一份力量,请移步贡献指南

以下为部分章节的教程,想学习更多 alovajs 的用法,欢迎来alova 官网学习。

alova中提供了useRequestuseWatcheruseFetcher三种 use hook 实现请求时机,由它们控制何时应该发出请求,同时将会为我们创建和维护状态化的请求相关数据,如loadingdataerror等,无需自主维护这些状态,下面我们来了解下它们。

本次我们先了解第一个 use hook,useRequest ,它表示一次请求的发送,执行useRequest时默认会发送一次请求,在页面获取初始数据时是最常用的方法,同时也支持关闭它的默认的请求发送,这在提交数据等通过点击事件触发的请求场景非常有用。

初始数据请求

我们来为 todo 列表获取页面数据。

vue

html 复制代码
<template>
  <!-- 你可以直接使用 data 来渲染 todo 列表 -->
  <div v-if="loading">Loading...</div>
  <div
    v-else-if="error"
    class="error">
    {{ error.message }}
  </div>
  <template v-else>
    <div v-for="todo in data">
      <div class="todo-title">{{ todo.title }}</div>
      <div class="todo-time">{{ todo.time }}</div>
    </div>
  </template>
</template>

<script setup>
  const {
    // loading是加载状态值,当加载时它的值为true,结束后自动更新为false
    // 它是一个Ref类型的值,你可以通过loading.value访问它,或直接绑定到界面中
    loading,

    // 响应数据,同样是Ref值
    data,

    // 请求错误对象,Ref值,请求错误时有值,否则为undefined
    error

    // 直接将Method实例传入即可发送请求
  } = useRequest(todoListGetter, {
    // 请求响应前,data的初始值
    initialData: []
  });
</script>

react

jsx 复制代码
const App = () => {
  const {
    // loading是加载状态值,当加载时它的值为true,结束后自动更新为false
    // 它的值为普通的boolean值,请求状态变化时内部将自动调用set函数更新它的值
    loading,

    // 响应数据
    data,

    // 请求错误对象,请求错误时有值,否则为undefined
    error

    // 直接将Method实例传入即可发送请求
  } = useRequest(todoListGetter, {
    // 请求响应前,data的初始值
    initialData: []
  });

  // 你可以直接使用 todoList 来渲染 todo 列表
  if (loading) {
    return <div>Loading...</div>;
  } else if (error) {
    return <div class="error">{error.message}</div>;
  } else {
    return (
      <>
        <div v-for="todo in data">
          <div class="todo-title">{todo.title}</div>
          <div class="todo-time">{todo.time}</div>
        </div>
      </>
    );
  }
};

svelte

html 复制代码
<script>
  const {
    // loading是加载状态值,当加载时它的值为true,结束后自动更新为false
    // 它是一个Writable类型的值,内部将维护它
    loading,

    // 响应数据
    data,

    // 请求错误对象,请求错误时有值,否则为undefined
    error

    // 直接将Method实例传入即可发送请求
  } = useRequest(todoListGetter, {
    // 请求响应前,data的初始值
    initialData: []
  });
</script>

<!-- 你可以直接使用 todoList 来渲染 todo 列表 -->
{#if $loading}
<div>Loading...</div>
{:else if $error}
<div class="error">{ $error.message }</div>
{:else} {#each $data as todo}
<div>
  <div class="todo-title">{ todo.title }</div>
  <div class="todo-time">{ todo.time }</div>
</div>
{/each} {/if}

绑定请求回调

如需设置请求回调,你还可以在 useRequest 的返回参数中接收回调的设置函数,如下:

javascript 复制代码
const {
  // ...

  // 成功回调绑定
  onSuccess,

  // 失败回调绑定
  onError,

  // 完成回调绑定,回调在成功或失败都会调用
  onComplete
} = useRequest(todoListGetter);
onSuccess(event => {
  console.log('请求成功,响应数据为:', event.data);
  console.log('本次请求的method实例为:', event.method);
  console.log('响应数据是否来自缓存:', event.fromCache);
});
onError(event => {
  console.log('请求失败,错误信息为:', event.error);
  console.log('本次请求的method实例为:', event.method);
});
onComplete(event => {
  // event.status在成功时为success,失败时为error
  console.log('请求完成,状态为:', event.status);
  console.log('本次请求的method实例为:', event.method);
  console.log('响应数据是否来自缓存:', event.fromCache);
  if (event.data) {
    console.log('请求数据:',event.data)
  } else if (event.error) {
    console.log('错误信息:',event.error)
  }
});

onSuccess中抛出错误将会触发onError

手动发送请求

当你需要创建一条新的 todo 项时,可以先关闭默认发送请求,转为手动触发请求,并在 useRequest 中接收send函数用于手动发送请求,send函数将返回带响应数据的 Promise 实例,它将在请求响应后改为 resolve 状态。

javascript 复制代码
const {
  // ...
  // 手动发送器请求的函数,调用后发送请求
  send: addTodo
} = useRequest(newTodo => alovaInstance.Post('/todo', newTodo), {
  // 当immediate为false时,默认不发出
  immediate: false
});

// 手动发送请求
const handleAddTodo = () => {
  const newTodo = {
    title: '新的todo项',
    time: new Date().toLocaleString()
  };
  // send函数返回一个Promise对象,可接收响应数据
  addTodo(newTodo)
    .then(result => {
      console.log('新增todo项成功,响应数据为:', result);
    })
    .catch(error => {
      console.log('新增todo项失败,错误信息为:', error);
    });
};

[2.9.0+]在 react 中,send 函数使用了useCallback包裹,同时它也不受闭包陷阱限制,你可以直接在事件中使用它,不用担心引起性能问题。

强制发送请求

缓存数据可以很好地提升应用流畅性和减小服务端压力,但同时也存在着数据过期的问题,当你希望穿透缓存获取最新数据时,在 use hooks 的配置中设置force属性可以帮助你。

设置静态值

force 默认为 false,设置为 true 时将每次穿透缓存,并发送请求

javascript 复制代码
useRequest(alovaInstance.Get('/todo'), {
  force: true
});

动态设置 force 值

实际情况中,我们经常需要根据不同情况来设置是否需要强制发送请求,此时可以将 force 设置为一个函数,此函数可通过 send 函数传入。

javascript 复制代码
const { send } = useRequest(alovaInstance.Get('/todo'), {
  force: id => {
    return !!id;
  }
});
send(1);

send 函数参数传递规则

在上面的示例中,调用 send 函数手动触发请求,它可以接受任意多个参数,这些参数将分别被以下 5 个函数接收:

在 useRequest 回调函数中接收

当 useRequest 的第一个参数设置为回调函数时可以接收到,这通常在删除列表项时很有用,具体如下:

javascript 复制代码
const { send } = useRequest(id => removeTodoPoster(id));
send(1); // 上面回调函数中的id将接收到1

在 onSuccess、onError、onComplete 回调函数中接收

onSuccess、onError、onComplete 回调函数中的event.sendArgs以数组形式接收

javascript 复制代码
const { send, onSuccess, onError, onComplete } = useRequest(newTodo => alovaInstance.Post('/todo', newTodo));
onSuccess(event => {
  // sendArgs的值为[1]
  console.log(event.sendArgs);
});
onError(event => {
  // sendArgs的值为[1]
  console.log(event.sendArgs);
});
onComplete(event => {
  // sendArgs的值为[1]
  console.log(event.sendArgs);
});

// 发送请求
send(1);

在 force 函数中接收

javascript 复制代码
const { send } = useRequest(alovaInstance.Get('/todo'), {
  force: id => {
    return !!id;
  }
});
send(1);

设置初始响应数据

一个页面在获取到初始数据前,不可避免地需要等待服务端响应,在响应前一般需要先将状态初始化为一个空数组或空对象,以免造成页面报错,我们可以在useRequest中的第二个参数实现初始数据的设置。

javascript 复制代码
// 在useRequest中设置初始数据
const {
  // 响应前data的初始值为[],而不是undefined
  // highlight-start
  data
} = useRequest(todoListGetter, {
  initialData: []
});
// highlight-end

手动修改状态值

在 alova 中,通过useRequest返回的dataloadingerror等各项状态是允许自定义修改的,这在一些情况下将变得很方便。

vue

javascript 复制代码
const { data, loading, error, update } = useRequest(todoListGetter);

// ...
// 直接修改data值
data.value = {};

// 或者通过update函数修改
update({
  data: {}
});

react

在 react 中,返回的状态是直接可使用的数据,因此需通过update函数来修改。

javascript 复制代码
const { data, loading, error, update } = useRequest(todoListGetter);

// ...
// 通过update修改data值
update({
  data: {}
});

svelte

在 svelte 中,useRequest返回的状态为writable类型。

javascript 复制代码
const { data, loading, error, update } = useRequest(todoListGetter);

// ...
// 直接修改data值
$data = {};
// 或data.update(d => ({}));

// 或者通过update函数修改
update({
  data: {}
});

注意事项

  1. 自定义修改的值将会被useRequest内部的状态管理机制覆盖,如当你修改了data值,再次请求后data值将被赋值为最新的响应数据;
  2. 通过直接修改的状态值不会同步修改缓存数据,如需要同步修改缓存数据,建议使用updateState

:::

手动中断请求

未设置timeout参数时请求是永不超时的,如果需要手动中断请求,可以在useRequest函数被调用时接收abort方法。

javascript 复制代码
const {
  // ...
  // highlight-start
  // abort函数用于中断请求
  abort
  // highlight-end
} = useRequest(todoListGetter);

// highlight-start
// 调用abort即可中断请求
const handleCancel = () => {
  abort();
};
// highlight-end

[2.9.0+]在 react 中,abort 函数使用了useCallback包裹,同时它也不受闭包陷阱限制,你可以直接在事件中使用它,不用担心引起性能问题。

[2.6.2+]另外,这个abort函数也会同时绑定到当前的 method 实例上,因此你也可以这样来中断请求。

javascript 复制代码
useRequest(todoListGetter);

// highlight-start
// 调用method上的abort也可以中断当前请求
const handleCancel = () => {
  todoListGetter.abort();
};
// highlight-end

[2.6.2+]你还可以在beforeRequest中调用abort中断请求。

javascript 复制代码
const alovaInst = createAlova({
  // ...
  beforeRequest(method) {
    if (someCondition) {
      method.abort();
    }
  }
});

为什么要使用alova

alova 也致力于解决客户端网络请求的问题,但与其他请求库不同的是,alova 选择了业务场景化请求策略的方向,它配合axios/fetch api等请求库后能满足你绝大部分请求需求(99%)的同时,还提供了丰富的高级功能。

  • 你可能曾经也在思考着应该封装fetchaxios,现在你不再需要这么做了,通过 alova 使用声明的方式完成请求,例如请求共享、分页请求、表单提交、断点上传等各种较复杂的请求,以及自动化缓存管理、请求共享、跨组件更新状态等。
  • alova 是轻量级的,只有 4kb+,是 axios 的 30%+。
  • 目前支持vue/react/react-native/svelte,以及next/nuxt/sveltekit等 SSR 框架,同时也支持Uniapp/Taro多端统一框架。
  • alova 是低耦合的,你可以通过不同的适配器让 alova 在任何 js 环境下,与任何 UI 框架协作使用(内置支持的 UI 框架为vue/react/svelte),并且提供了统一的使用体验和完美的代码迁移。
  • 使用 alova 还能实现 api 代码的高聚合组织方式,每个 api 的请求参数、缓存行为、响应数据转换等都将聚集在相同的代码块中,这对于管理大量的 api 有很大的优势。

与其他请求库的对比

多框架支持

现在,你还可以在 vue options(vue2 和 vue3) 写法中完美使用 alova,点此查看详情。后续我们将陆续支持以下框架:

  • 函数式,如solid/preact/qwik
  • class 式,如angular/lit/stencil
  • options 式,如原生小程序(中国🇨🇳)

alovajs 还提供了其他强大的请求策略:

名称 描述 文档
分页请求策略 自动管理分页数据,数据预加载,减少不必要的数据刷新,流畅性提高 300%,编码难度降低 50% usePagination
无感数据交互策略 全新的交互体验,提交即响应,大幅降低网络波动造成的影响,让你的应用在网络不稳定,甚至断网状态下依然可用 useSQRequest
表单提交策略 为表单提交而设计的 hook,通过此 hook 你可以很方便地实现表单草稿、多页面(多步骤)表单,除此以外还提供了表单重置等常用功能 useForm
文件上传策略 更简单的文件上传策略,支持对 base64、Blob、ArrayBuffer、Canvas 数据的自动识别和转换 useUploader
发送验证码 验证码发送 hook,减掉你在开发验证码发送功能时的繁琐。 useCaptcha
自动重新拉取数据 在一定条件下自动重新拉取数据,保证始终展示最新数据。 useAutoRequest
跨组件触发请求 一个 alova 中间件,消除组件层级的限制,在任意组件中快速地触发任意请求的操作函数 actionDelegationMiddleware
串行请求的 useRequest alova 的串行请求方式更加简洁易用的串行请求 use hook,提供统一的 loading 状态、error、回调函数 useSerialRequest
串行请求的 useWatcher alova 的串行请求方式更加简洁易用的串行请求 use hook,提供统一的 loading 状态、error、回调函数。 useSerialWatcher
请求重试策略 请求失败自动重试,它在重要的请求和轮询请求上发挥重要作用 useRetriableRequest
SSE 请求 通过 Server-sent Events 进行请求 useSSE

想学习更多 alovajs 的用法,欢迎来alova 官网学习。如果你也喜欢 alovajs,请在Github 仓库中贡献一颗 star,这对我们非常重要。

如果觉得文章对你有帮助,请别吝啬你的赞和评论哈,说说你对 alovajs 怎么看的,或者可以问一些问题,我会尽量回答的,你的支持是我创作的最大动力!哈哈哈哈哈哈~

欢迎加入交流社区

有任何问题,你可以加入以下群聊咨询,也可以在github 仓库中发布 Discussions,如果遇到问题,也请在github 的 issues中提交,我们会在最快的时间解决。

同时也欢迎贡献你的一份力量,请移步贡献指南

往期文章

相关推荐
Jiaberrr1 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
LvManBa2 小时前
Vue学习记录之六(组件实战及BEM框架了解)
vue.js·学习·rust
200不是二百2 小时前
Vuex详解
前端·javascript·vue.js
LvManBa2 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
深情废杨杨2 小时前
前端vue-父传子
前端·javascript·vue.js
工业互联网专业3 小时前
毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
J不A秃V头A3 小时前
Vue3:编写一个插件(进阶)
前端·vue.js
光影少年4 小时前
usemeno和usecallback区别及使用场景
react.js
司篂篂4 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客4 小时前
pinia在vue3中的使用
前端·javascript·vue.js