阅读 1219

vue3 setup语法糖学习之路(一)-- useRequest

前言

本系列仅为记录个人学习vue3setup语法糖过程中遇到的问题及解决方法和思路。

一、问题

在一个偶然的机会看到了这篇文章,感觉useSWR就很nice。结果在npm上找到vue-swr后,发现该插件最后更新是两年前,Emmmm,算了还是自己手动实现吧。

image.png

二、实现

过程就不详诉了,踩了很多坑,也是因为对vue3不够熟悉,简单讲下注意点吧。

1. ref、reative、toRefs

虽然最后实现只用到了ref,但是在实现过程中一直搞不清用ref、reative、toRefs的哪一个还是要混着用,晕头转向的。所以还是拎出来讲清楚他们之间的关系和区别。

  • ref

用来定义一个响应式变量,取值时需要用.value获取。

import { ref } from 'vue' let count = ref(0) let userInfo = ref({   name:'张三',   age:18 }) 复制代码

看一下控制台打印的

image.png 通过ref创建的响应式对象为RefImpl对象

  • reative

reative通常用来定义一个响应式数组或对象,取值按照普通对象、数组的取值方式即可,

import { reactive } from 'vue' let userInfo = reactive({   name: '张三',   age: 18, }) 复制代码

看一下控制台打印的

image.png 通过reative创建的响应式对象为Proxy对象

  • toRefs

reative创建的响应式对象转换成一个属性值为ref创建的响应式值的普通对象

import { toRefs, reactive } from 'vue' let userInfo = reactive({   name: '张三',   age: 18, }) let userInfoRefs = toRefs(userInfo) 复制代码

看一下控制台打印的

image.png 通过修改userInfoRefs的属性值也会同步修改userInfo的相应属性值

userInfoRefs.age.value = 88 复制代码

image.png

2. 实现思路,正文开始

  • 由于setup语法糖只有在顶层的变量才能在模板中使用,因此先在setup顶层中定义一个响应式listInfo。注意:listInfo不可指向其他任何数据(包括其他的响应式变量),否则跟模板的响应式会断开。

<script setup> import { ref } from 'vue' // 定义顶层变量 let listInfo = ref({   loading: false,   data: null,   error: null, }) </script> <template>   <p>loading:{{ listInfo.loading }}</p>   <p>data:{{ listInfo.data }}</p>   <p>error:{{ listInfo.error }}</p> </template> 复制代码

此时页面展示如下

image.png

  • 模拟获取数据

<script setup> import { ref, onMounted } from 'vue' import { useRequest } from '@/hooks/request' // 模拟接口 let api = (params) => {   return new Promise((resolve, reject) => {     setTimeout(() => {       resolve('11111111111')     }, 1000)   }) } // 获取数据方法 function fetchData() {   let params = {}   let res = useRequest(api, params) } // 页面挂载后获取数据 onMounted(() => {    fetchData() }) </script> 复制代码

  • 现在就要实现useRequest。思考一下,useRequest是个同步方法,如何异步更新顶层变量的数据?其实只要useRequest返回响应式数据,并且将顶层变量指向这个响应式数即可。

// src/hooks/request.js import { ref } from 'vue' export function useRequest(api, params) {   let loading = ref(false)   let error = ref()   let data = ref()   // loading-start   loading.value = true   // 获取数据   api(params)     // 成功     .then((res) => {       //set data       data.value = res       // loading-end       loading.value = false     })     // 失败     .catch((e) => {       // set error       error.value = e       console.error(e)       // loading-end       loading.value = false     })   return {     loading,     data,     error,   } } 复制代码

此时实现了useRequest返回响应式数据,只要让顶层变量指向这个数据就大公告成。

<script setup> import { ref, onMounted } from 'vue' import { useRequest } from '@/hooks/request' // 定义顶层变量 let listInfo = ref({   loading: false,   data: null,   error: null, }) // 获取数据方法 function fetchData() {   let params = {}   let res = useRequest(api, params)      // 直接赋值(×)   // listInfo = res    // 前面提到过 如果将listInfo指向任意值都会导致响应式断开      // 由于useRequest返回的是由ref生成的响应式变量组成的普通对象   // 只要将res的值赋值给对应的userInfo的属性即可     Object.assign(listInfo.value, res) } </script> 复制代码

三、优化一下

因为平时接口获取到值的格式与模板渲染的格式不一定一致,所以需要一个转换格式的功能。

<script setup> import { ref, onMounted } from 'vue' import { useRequest } from '@/hooks/request' // 获取数据方法 function fetchData() {   //数据格式化、举个栗子   let fmt = (data) => {     return 'data' + data   }   let params = {}   let res = useRequest(api, params, fmt) } </script> 复制代码

// src/hooks/request.js import { ref } from 'vue' export function useRequest(api, params,fmt) {  ...   api(params)     // 成功     .then((res) => {       //set data       data.value = fmt ? fmt(res) : res     }) ... } 复制代码

四、整合一下

<script setup> import { ref, onMounted } from 'vue' import { useRequest } from '@/hooks/request' // 定义顶层变量 let listInfo = ref({   loading: false,   data: null,   error: null, }) // 模拟接口 let api = (params) => {   return new Promise((resolve, reject) => {     setTimeout(() => {       resolve('11111111111')     }, 1000)   }) } // 获取数据方法 function fetchData() {   //数据格式化、举个栗子   let fmt = (data) => {     return 'data' + data   }   let params = {}   let { loading, data, error } = useRequest(api, params)   Object.assign(listInfo.value,{ loading, data, error }) } // 页面挂载后获取数据 onMounted(() => {    fetchData() }) </script> <template>   <p>loading:{{ listInfo.loading }}</p>   <p>data:{{ listInfo.data }}</p>   <p>error:{{ listInfo.error }}</p> </template> 复制代码

// src/hooks/request.js import { ref } from 'vue' export function useRequest(api, params, fmt) {   let loading = ref(false)   let error = ref()   let data = ref()   //loading-start   loading.value = true   //获取前数据   api(params)     //成功     .then((res) => {       //set data       data.value = fmt ? fmt(res) : res       //loading-end       loading.value = false     })     //失败     .catch((e) => {       //set error       error.value = e       console.error(e)       //loading-end       loading.value = false     })   return {     loading,     data,     error,   } }


作者:Xyuan_
链接:https://juejin.cn/post/7021451205641502734


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐