Vue3 转 React:组件透传 Attributes 与 useAttrs 使用详解|VuReact 实战

0 阅读2分钟

在 Vue3 迁移 React、跨框架组件封装的场景里,透传 Attributes 是几乎必用、但极易踩坑的能力。Vue 的 $attrs / useAttrs 和 React 的 props 体系设计差异很大,而 VuReact 作为稳定的 Vue3 → React 编译工具,已经把这套逻辑做了完整对齐。

本文带你一次性搞懂:透传属性是什么、为什么必须用 useAttrs、TS 怎么写、转换后长什么样,直接复制就能用。


一、先搞懂:透传 Attributes 到底是什么?

1. Vue 官方定义

透传 attribute:传给组件,但没有被声明为 props / emits 的属性或事件监听器。 最常见:classstyleid、自定义属性、v-on 监听等。

Vue 默认会把它们自动继承到组件根节点,也可以用 $attrsuseAttrs() 手动控制。

2. React 里的等价逻辑

React 没有“透传”这个名词,但行为一致: 所有没在 Props 里定义的属性,都属于“透传属性”,全部挂在 props 上。

区别是:

  • Vue:运行时自动处理
  • React + TS:必须显式写类型,否则报错

3. VuReact 的核心适配规则

VuReact 把透传属性统一理解为: 无类型约束的运行时对象 + 已声明 Props 合并 = 最终组件属性

  • 组件无 Props → 自动生成:props: Record<string, unknown>
  • 组件有 Props → 自动交叉类型:Props & Record<string, unknown>

二、关键:必须从 $attrs 转向 useAttrs()

Vue 里有两种写法:

  • $attrs:运行时隐式变量 → VuReact 无法静态分析
  • useAttrs():显式 API → VuReact 完美支持、推荐唯一写法

1. Vue 中标准 useAttrs 写法(必背)

<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>

好处:

  • 编译器可静态识别
  • 支持 TS 类型注解
  • 符合 React“显式优于隐式”的习惯

2. VuReact 转换规则(一张表看懂)

Vue useAttrs 写法React 转换结果
无类型const attrs = props as Record<string, unknown>
类型断言 as Attrsconst attrs = props as Attrs
变量带类型 attrs: Attrsconst attrs = props as Attrs
搭配 definePropsProps & Record<string, unknown>

三、实战示例:从 Vue 到 React 完整对照

示例 1:基础用法(无 TS)

Vue 输入

<template>
  <div :class="attrs.class" :style="attrs.style">
    {{ attrs.title }}
  </div>
</template>

<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>

React 输出

import { memo } from 'react'

const Comp = memo((props: Record<string, unknown>) => {
  const attrs = props as Record<string, unknown>

  return (
    <div className={attrs.class} style={attrs.style}>
      {attrs.title}
    </div>
  )
})

export default Comp

示例 2:TS 类型增强(企业级推荐)

Vue 输入

<template>
  <div :class="attrs.class" :style="attrs.style">
    {{ attrs.customTitle }}
  </div>
</template>

<script setup lang="ts">
import { useAttrs } from 'vue'

interface CustomAttrs {
  class?: string
  style?: React.CSSProperties
  customTitle?: string
  [key: string]: unknown
}

const props = defineProps<{
  id: string
}>()

const attrs = useAttrs() as CustomAttrs
</script>

React 输出

import { memo } from 'react'

interface CustomAttrs {
  class?: string
  style?: React.CSSProperties
  customTitle?: string
  [key: string]: unknown
}

type ICompProps = { id: string }

const Comp = memo((props: ICompProps & Record<string, unknown>) => {
  const attrs = props as CustomAttrs

  return (
    <div className={attrs.class} style={attrs.style}>
      {attrs.customTitle}
    </div>
  )
})

export default Comp

示例 3:动态属性 / 可选链(真实业务常用)

Vue 输入

<template>
  <div
    :class="[
      'base',
      attrs.class,
      attrs.xx?.class,
      attrs['custom-class']
    ]"
  >
    {{ attrs?.xxx?.content }}
  </div>
</template>

React 输出

import { memo } from 'react'
import { dir } from '@vureact/runtime-core'

const Comp = memo((props: Record<string, unknown>) => {
  const attrs = props

  return (
    <div
      className={dir.cls([
        'base',
        attrs.class,
        attrs.xx?.class,
        attrs['custom-class']
      ])}
    >
      {attrs?.xxx?.content}
    </div>
  )
})

四、避坑指南(VuReact 必看)

  1. 必须用 useAttrs(),禁止用 $attrs 编译器无法分析运行时变量,会丢属性。

  2. TS 尽量写接口 有利于提示、重构、避免空值报错。

  3. class/style 自动适配 classclassName style → 自动适配 React.CSSProperties

  4. defineProps + useAttrs 会自动合并类型 不用手动改。

  5. JS 项目直接用 会被编译成 const attrs = props,完全兼容。


五、总结

VuReact 处理透传 Attributes 的核心思想只有一句话: 把 Vue 隐式的 $attrs 变成显式的 useAttrs,再映射到 React 的 props 体系。

  • 你只管按 Vue 官方写法写
  • 编译器自动转成标准 React TSX
  • 类型安全、生产可用、迁移成本极低

正在做 Vue3 → React 迁移的同学,这套透传方案可以直接进团队规范。


🔗 相关资源


推荐阅读

#Vue3 #React #Vue转React #VuReact #前端迁移 #useAttrs #组件封装 #TypeScript