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

相关推荐
xiguolangzi19 分钟前
vue3+element-plus el-table列的显隐、列宽 持久化
前端·javascript·vue.js
大猩猩X1 小时前
vxe-upload vue 实现附件上传、手动批量上传附件的方式
vue.js·vxe-ui
come112341 小时前
Vue 响应式数据传递:ref、reactive 与 Provide/Inject 完全指南
前端·javascript·vue.js
海天胜景3 小时前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼4 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
百锦再4 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5554 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架
木头没有瓜5 小时前
vscode离线安装插件
ide·vue.js·vscode
浪裡遊6 小时前
Sass详解:功能特性、常用方法与最佳实践
开发语言·前端·javascript·css·vue.js·rust·sass
markyankee1017 小时前
使用 Vue 脚手架创建项目的完整指南
vue.js