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

相关推荐
VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue云租车平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
小安驾到1 小时前
【前端的坑】vxe-grid表格tooltip提示框不显示bug
前端·vue.js
计算机学姐2 小时前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法
Liu.7743 小时前
vue开发h5项目
vue.js
pas1364 小时前
42-mini-vue 实现 transform 功能
前端·javascript·vue.js
柒.梧.4 小时前
从零搭建SpringBoot+Vue+Netty+WebSocket+WebRTC视频聊天系统
vue.js·spring boot·websocket
毕设源码-钟学长4 小时前
【开题答辩全过程】以 基于node.js vue的点餐系统的设计与实现为例,包含答辩的问题和答案
前端·vue.js·node.js
小白路过4 小时前
记录vue-cli-service serve启动本地服务卡住问题
前端·javascript·vue.js
梵得儿SHI5 小时前
Vue 高级特性:渲染函数与 JSX 精讲(h 函数语法、JSX 在 Vue 中的应用)
前端·javascript·vue.js·jsx·模板语法·渲染函数·底层视图生成机制
David凉宸5 小时前
Vue 3 项目的性能优化策略:从原理到实践(页面展示)
javascript·vue.js·性能优化