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语法糖的全部内容,如果你有更好的办法可以评论区留言,我也会虚心的学习

相关推荐
雨中奔跑的小孩16 分钟前
electron打包部署vue项目
javascript·vue.js·electron
光影少年2 小时前
react和vue图片懒加载及实现原理
前端·vue.js·react.js
胡图蛋.2 小时前
vue的理解
vue.js
GISer_Jing4 小时前
Vue3常见Composition API详解(适用Vue2学习进入Vue3学习)
前端·javascript·vue.js
计算机学姐4 小时前
基于SSM的宠物领养平台
java·vue.js·spring·maven·intellij-idea·mybatis·宠物
工业互联网专业5 小时前
Python毕业设计选题:基于django+vue的期货交易模拟系统的设计与实现
vue.js·python·django·毕业设计·源码·课程设计
悦涵仙子5 小时前
vueuse中的useTemplateRefsList
前端·javascript·vue.js
NightCyberpunk5 小时前
Ajax与Vue初步学习
vue.js·学习·ajax
橙某人6 小时前
微前端(qiankun)之应用间的通信方案-发布订阅
前端·vue.js·微服务
理想不理想v6 小时前
前端开发工程师需要学什么?
java·前端·vue.js·webpack·node.js