vue3+tsx/jsx+setup语法糖 ref获取多个dom

当你能找到这个文章的时候,代表你的页面已经崩溃了,并且很遗憾的告诉你,当我们本地调试代码的时候会发现没问题,当时当你build之后运行......(试试就逝世)

这个黄色警告什么意思啊,翻译过来就是,"组件<Render>中超过了最大递归更新。这意味着您有一个反应性效果,它正在改变自己的依赖关系,从而递归地触发自己。可能的源包括组件模板、渲染函数、更新的钩子或观察者源函数。"

这个问题怎么产生的?

我写一个简单的demo,下面的代码是否存在问题

xml 复制代码
<template>
  <render />
</template>

<script setup lang="tsx">
import {ref} from 'vue'
interface option {
  label:string,
  value:number
}
const list:option[] = []
for (let i=0;i<10;i++){
  list.push({
    label:'我是'+i,
    value:i
  })
}
const listRef = ref<HTMLDivElement[]>([])

const Render = () => {
  return (
      <>
        {
          list.map((row:option)=>{
            return (
                <div
                  key={row.value}
                  ref={e=>e&&listRef.value.push(e as HTMLDivElement)}>
                  {row.label}
                </div>
            )
          })
        }
      </>
  )
}
</script>

如果你把这段代码copy去执行,发现一点问题都没有,并且能够正常运行,那这段代码究竟有没有问题,我们一点点分析

vue2获取ref

vue2中ref获取方式应该不陌生,我这里直接使用vue2.x官方的例子

csharp 复制代码
// html
<base-input ref="usernameInput"></base-input>

// js
this.$refs.usernameInput

从vue2的官网文档可以看出当单个ref就是直接访问的对象,结合v-for的时候就是一个数组

那vue2官方都有说,vue3应该也是有的

vue3获取ref

在vue3的文档上面很遗憾没有ref结合v-for的使用。那既然没有结合的例子,那我们就找下jsx的创始人------react16

在react文档中找到应该也满足vue写法例子------回调Refs

原来ref是可以传递回调函数的,通过尝试发现在vue中也是能使用的,那就应该得到我们一开始写的代码。很好,解决获取多个ref的问题了,下班。

但是如果我把这个简单的demo复杂那么一点点会不会出现不一样的问题,请看demo

vue 复制代码
<template>
  <render />
</template>

<script setup lang="tsx">
import {ref} from 'vue'
interface option {
  label:string,
  value:number
}
const list:option[] = []
for (let i=0;i<10;i++){
  list.push({
    label:'我是'+i,
    value:i
  })
}
const listRef = ref<HTMLDivElement[]>([])
const count = ref<number>(0);


const Render = () => {
  return (
      <>
        {
          list.map((row:option)=>{
            return (
                <div
                  key={row.value}
                  ref={e=>e&&listRef.value.push(e as HTMLDivElement)}>
                  {row.label}
                </div>
            )
          })
        }
        {count.value} 
         <button onClick={()=>count.value+=1}>添加</button>
      </>
  )
}
</script>

添加一个累加的按钮,在chrome打开vue的插件看下setup的变量

很好,数据没有没问题。当我们点击一下按钮,让那个count进行累加之后再看一遍setup的数据

就会发现,原本listRef的长度是10,现在是20并且里面也是div,那这个20 - 10 = 10的这个差距怎么来的。那就再点按钮,重复我们的操作,就能发现这个长度10的数据也正是div标签。简单的思考一下,这个问题就是回调Refs的问题。

查看一下vue的生命周期,当组件 mounted 之前执行了一次render(这里的render不是demo中的render组件)然后当有数据更新就会再执行一次render(这一次的render就额外添加多了一次数据就导致了listRef数据越来越长)

结合以上原因得到修改后的代码

vue 复制代码
<template>
  <render />
</template>

<script setup lang="tsx">
import {ref} from 'vue'
interface option {
  label:string,
  value:number
}
const list:option[] = []
for (let i=0;i<10;i++){
  list.push({
    label:'我是'+i,
    value:i
  })
}
const listRef = ref<HTMLDivElement[]>([])
const count = ref<number>(0);


const Render = () => {
  return (
      <>
        {
          list.map((row:option)=>{
            return (
                <div
                  key={row.value}
                  ref={e=>listRef.value[index] = e as HTMLDivElement}>
                  {row.label}
                </div>
            )
          })
        }
        {count.value} 
         <button onClick={()=>count.value+=1}>添加</button>
      </>
  )
}
    
    
// 下面这种方式我不太建议,更改了listRef.value原本的数据原型链,回触发额外不必要的数据响应
// const Render = () => {
//   listRef.value = []
//   return (
//       <>
//         {
//           list.map((row:option)=>{
//             return (
//                 <div
//                     key={row.value}
//                     ref={e=>e&&listRef.value.push(e as HTMLDivElement)}>
//                   {row.label}
//                 </div>
//             )
//           })
//         }
//         {count.value}
//         <button onClick={()=>count.value+=1}>添加</button>
//       </>
//   )
// }
</script>

以上就是vue3+tsx/jsx+setup语法糖的全部内容,如果你有更好的办法可以评论区留言,我也会虚心的学习

相关推荐
万叶学编程3 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
积水成江6 小时前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
计算机学姐6 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
老华带你飞6 小时前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计
qbbmnnnnnn7 小时前
【WebGis开发 - Cesium】如何确保Cesium场景加载完毕
前端·javascript·vue.js·gis·cesium·webgis·三维可视化开发
杨荧8 小时前
【JAVA开源】基于Vue和SpringBoot的水果购物网站
java·开发语言·vue.js·spring boot·spring cloud·开源
霸王蟹9 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
老章学编程i10 小时前
Vue工程化开发
开发语言·前端·javascript·vue.js·前端框架
tanxiaomi11 小时前
vue 不是spa 单页面应用吗? 配置路由工作模式为history 后 ,为什么配置Nginx的 try_files 可以根据url 找到对应的文件?
前端·vue.js·nginx
果子切克now11 小时前
vue3导入本地图片2种实现方法
前端·javascript·vue.js