Vue3 Hooks 探索

背景

众所周知 Vue3 的时代已来临, Vue3中推荐使用组合式Api, 也就是由之前的类编程转换为函数式编程,逻辑转移到setup语法糖中,由setup作为组合式API的入口点。作为函数式编程Hooks是必不可少的,因为笔者之前一直使用React,在React中 AHooks 是封装的较为全面且实用的hooks库,但是到了Vue3中一直没有找到合适的库,后来决定自己写一套Hooks库,也就是有了 V3Hooks 这个库, 接下来会拿出几个Hook来做介绍,如果这对你有帮助的话,可以给一个Star支持。

使用

接下来我们看几个常用的Hook使用

useRequest

useRequest是用于管理异步请求的Hook,针对于需求中常见的请求发起方式进行封装,加速你的日常开发,他具有以下功能:

  • 自动请求/手动请求
  • SWR(stale-while-revalidate)
  • 缓存/预加载
  • 屏幕聚焦重新请求
  • 轮询
  • 防抖
  • 节流
  • 依赖请求
  • 突变
  • loading delay

请求发起方式

如果service是object,useRequest会使用 Fetch 来发送网络请求

import { useRequest } from 'v3hooks';
const { data } = useRequest(
    {
    url: 'http://xxx.xx.com/api/userInfo',
    method: 'POST'
    }
);

如果service是async函数,useRequest会调用此函数来发送网络请求

import { useRequest } from 'v3hooks';
const { data } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
);

基础请求

import { useRequest } from 'v3hooks';
const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
);
watchEffect(()=>{
    console.log( data?.value );
})

在这个例子中, useRequest 接收了一个异步函数 ,在组件初次加载时, 自动触发该函数执行。同时 useRequest 会自动管理异步请求的 loading , data 状态。你可以通过data和loading来实现你的需求

因为返回的data为响应式,js中获取data.value需要在watchEffect中使用,而在template中使用是不需要的。

手动触发

const { data, run, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        manual: true
    }
);

通过设置 options.manual = true , 则需要手动调用 run 时才会触发执行异步函数。

轮询

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        pollingInterval: 1000
    }
);

通过设置 options.pollingInterval ,进入轮询模式,定时触发函数执行。

依赖请求

import { onMounted, ref } from 'vue'

const isReady = ref(false);
const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        ready: isReady
    }
);
onMounted(() => {
    isReady.value = true;
})

只有当 options.ready 变为 true 时, 才会发起请求,基于该特性可以实现串行请求,依赖请求等。

防抖

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        debounceInterval: 1000
    }
);

通过设置 options.debounceInterval ,则进入防抖模式。此时如果频繁触发 run ,则会以防抖策略进行请求。

节流

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        throttleInterval: 1000
    }
);

通过设置 options.throttleInterval ,则进入节流模式。此时如果频繁触发 run ,则会以节流策略进行请求。

缓存 & SWR

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        caccacheKey: 'mock1'
    }
);

如果设置了 options.cacheKey , useRequest 会将当前请求结束数据缓存起来。下次组件初始化时,如果有缓存数据,我们会优先返回缓存数据,然后在背后发送新请求,也就是 SWR 的能力。你可以通过 cacheTime 设置缓存数据回收时间,也可以通过 staleTime 设置数据保持新鲜时间。

预加载

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        caccacheKey: 'mock1'
    }
);

同一个 cacheKey 的请求,是全局共享的,也就是你可以提前请求数据。后续请求会提前返回之前预加载的数据,利用该特性,可以很方便的实现预加载。

屏幕聚焦重新请求

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        refreshOnWindowFocus: true,
        focusTimespan: 2000
    }
);

如果你设置了 options.refreshOnWindowFocus = true ,则在浏览器窗口 refocus 和 revisible 时,会重新发起请求。你可以通过设置 options.focusTimespan 来设置请求间隔,默认无 。

突变

const { data, mutate } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    }
);

<button type="button" @click={() => mutate({code:'1',msg:'test'})}>
    突变测试
</button>

你可以通过 mutate ,直接修改 data.

Loading Delay

const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        loadingDelay: 300
    }
);

通过设置 options.loadingDelay ,可以延迟 loading 变成 true 的时间,有效防止闪烁。

refreshDeps

开发中会经常碰到这个需求,当某些 state 变化时,我们需要重新执行异步请求,使用useRequest将很方便的实现此功能。

import { onMounted, ref } from 'vue'

const random = ref(1);
const { data, loading } = useRequest(
    () => {
        return axios.post(
            `http://xxx.xx.com/api/userInfo`
        );
    },
    {
        refreshDeps: [ random ]
    }
);

setInterval(()=>{
    random.value = Math.random()
},1000)

当例子中 random 发生变化时,会重新执行 service。

useVirtualList

长列表虚拟化列表的 Hook,用于解决展示海量数据渲染时首屏渲染缓慢和滚动卡顿问题。

基础使用

<template>
  <div class="hello">
    <button
      style="margin-top: 30px"
      type="button"
      @click="handleVirtualScrollTo"
    >
      scroll to
    </button>
    <div
      :ref="containerProps.ref"
      @scroll="containerProps.onScroll"
      style="height: 300px; overflow: auto;border: 1px solid #cccccc"
    >
      <div :style="wrapperStyle">
        <div
          v-for="active in list"
          :key="active"
          style="
            height: 59px;
            border-bottom: 1px solid #cccccc;
            background-color: white;
          "
        >
          {{ active }}
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { useVirtualList } from "v3hooks";

export default {
  
  setup() {
    const { list, wrapperStyle, containerProps, scrollTo } = useVirtualList(
      Array.from(Array(99999).keys()),
      {
        itemHeight: 60,
        overscan: 10,
      }
    );

    const handleVirtualScrollTo = () => {
      scrollTo(22);
    };

    return {
      list,
      wrapperStyle,
      containerProps,
      handleVirtualScrollTo,
    };
  },
};
</script>

useVirtualList接受一个数组,导出一个虚拟化的list以元素配置,具体配置看Api

useTextSelection

实时获取用户当前选取的文本内容及位置的hook。

useTextSelection接受一个HTMLElement, 导出已选择的文本和位置信息。

基础使用

<template>
  <div style="text-align: center">
    <p ref="p"> 可选择区域: 123111111111111aaaaaaaaaaabbbbbbbbbbb eeeeeeeeeeeeeeee</p>
    <p>已选择的值:{{ text }}</p>
    <p>位置信息:rect: {{ rect }}</p>
    <p>left: {{ rect.left }}</p>
  </div>
</template>

<script lang="ts">
import { useTextSelection } from "v3hooks";
export default {
  setup() {
    const { text, rect } = useTextSelection();
    return {
        text,
        rect
    };
  },
};
</script>

没有传值默认为document, 页面上可选择的文本都会被计算

监听特定区域文本选择

<template>
  <div style="text-align: center">
    <p ref="p"> 可选择区域: 123111111111111aaaaaaaaaaabbbbbbbbbbb eeeeeeeeeeeeeeee</p>
    <p>已选择的值:{{ text }}</p>
    <p>位置信息:rect: {{ rect }}</p>
    <p>left: {{ rect.left }}</p>
  </div>
</template>

<script lang="ts">
import { ref } from 'vue';
import { useTextSelection } from "v3hooks";

export default {
  setup() {
    const p = ref();
    const { text, rect } = useTextSelection(p);

    return {
        text,
        p,
        rect
    };
  },
};
</script>

传值为Ref的P标签,只会监听特定区域。

useQRCode

一个用来生成二维码的 Hook 。

基础使用

<template>
  <div class="hello">
    <div> 二维码:</div>
    <img :src="state" alt="">
  </div>
</template>

<script lang="ts">
import { ref } from 'vue';
import { useQRCode } from "../../../dist/index.js";

const logo = require('../../assets/logo.png')

export default {
  
  setup() {
    const text = ref<string>('https://www.baidu.com/')

    const state = useQRCode(text,{
      logo: logo.default,
      colorDark: '#000000'
    });

    setTimeout(()=>{
      text.value = 'https://www.acfun.cn/'
    },2000)

    return {
      state
    };
  },
};
</script>

usQRCide可以接受一个静态url,也可以是一个被Ref包裹的url,当Ref值发生变化时,二维码会跟随内容进行变化。

useNetwork

一个用来获取当前网络状态的 Hook 。

基础使用

<template>
  <div class="hello" style="display:flex;align-items:flex-start;">
    <p> 网络状态:{{ state }}</p>
  </div>
</template>

<script lang="ts">
import { useNetwork } from "v3hooks";

export default {
  
  setup() {
    // 获取query中的a
    const state = useNetwork();

    // useVirtualList测试
    return {
      state
    };
  },
};
</script>

useNetwork返回网络状态信息

结尾

以上拿出了几个Hooks来给大家演示,V3Hooks中还有很多实用Hooks来供大家使用,具体使用可以查看文档,附上 GitHub链接,希望这对你有用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容