Vue withDefaults 转 React:VuReact 怎么处理?

📅 2026/7/2 20:18:30 👁️ 阅读次数 📝 编程学习
Vue withDefaults 转 React:VuReact 怎么处理?

VuReact 是专为 Vue 迁移 React 设计的智能编译器。它用于将 Vue 3 单文件组件・脚本・样式完整转为纯 React(非运行时桥接)代码并输出工程化产物,覆盖<script setup>核心全特性,支持渐进式迁移与 Vue+React 混合开发。

今天就带大家直击核心:Vue 中常见的withDefaults编译宏经过 VuReact 编译后会变成什么样的 React 代码?

前置约定

为避免示例代码冗余导致理解偏差,先明确几个小约定:

  1. 文中 Vue / React 代码均为核心逻辑简写,省略完整组件包裹、无关配置等内容;
  2. 默认读者已熟悉 Vue 3 中withDefaults的 API 用法与核心行为;
  3. withDefaults()必须赋值给一个变量;
  4. 第一个参数必须是defineProps()调用,第二个参数必须是内联对象字面量。

编译对照

withDefaults 基础用法

withDefaults是 Vue 3<script setup>中用于为defineProps声明的 prop 提供编译时默认值的工具函数。Vue 中withDefaults会在编译时生成默认值逻辑,确保父组件未传递的 prop 拥有默认值。VuReact 会将它编译为useMemo在组件初始化时合并传入的 props 与默认值,生成一个包含完整默认值的只读 props 对象

  • Vue 代码:
<script setup lang="ts">interfaceProps{msg?:string;count?:number;labels:string[];}constprops=withDefaults(defineProps<Props>(),{msg:'hello',count:42,labels:()=>['one','two'],});</script>
  • VuReact 编译后 React 代码:
import{useMemo,memo}from'react';interfaceProps{msg?:string;count?:number;labels:string[];}exporttypeICompProps=Props;constInput=memo((vrProps:ICompProps)=>{/* from withDefaults */constprops=useMemo<Readonly<Props>>(()=>({...vrProps,msg:vrProps.msg??'hello',count:vrProps.count??42,labels:vrProps.labels??['one','two'],}),[vrProps]);});

从示例可以看到:Vue 的withDefaults被编译为 React 的useMemo+ 空值合并运算符??组合。主要分为三部分:

  1. 类型保留Props接口原样保留,不会因默认值而改变类型的可选/必填约束msg?count?仍是可选类型;
  2. 默认值合并useMemo中使用展开运算符...vrProps保留所有传入值,再对每个具有默认值的字段通过??空值合并运算符进行回退填充;
  3. 只读保证useMemo<Readonly<Props>>确保返回的 props 对象是只读的,与 Vue 中withDefaults的运行时不可变性一致。

核心行为:VuReact 保证组件内通过props.xxx访问的始终是包含默认值的完整属性集,与 Vue 开发体验完全一致。


基本类型默认值

对于stringnumber等基本类型的默认值,VuReact 直接使用??空值合并运算符:

  • Vue 代码:
<script setup lang="ts">constprops=withDefaults(defineProps<Props>(),{msg:'hello',count:42,});</script>
  • VuReact 编译后 React 代码:
constprops=useMemo(()=>({...vrProps,msg:vrProps.msg??'hello',count:vrProps.count??42,}),[vrProps]);

字段选项处理规则

  1. default: ‘hello’:通过??空值合并运算符实现,仅在父组件未传递该 prop(即undefined)时生效
  2. default: 42:基本类型默认值直接作为??右侧的字面量值
  3. 类型保留Propsmsg?count?的可选性不受默认值影响

引用类型默认值

对于数组、对象等引用类型,Vue 的withDefaults要求使用工厂函数(如() => ['one', 'two'])以避免多个实例共享同一引用。VuReact 同样遵循这一约定,直接在??右侧调用工厂函数,保证每次渲染生成独立的引用实例

  • Vue 代码:
<script setup lang="ts">interfaceProps{labels:string[];}constprops=withDefaults(defineProps<Props>(),{labels:()=>['one','two'],});</script>
  • VuReact 编译后 React 代码:
constprops=useMemo<Readonly<Props>>(()=>({...vrProps,labels:vrProps.labels??['one','two'],}),[vrProps]);

VuReact 保证??右侧的工厂函数每次执行都会返回新实例,避免引用共享导致的副作用污染。

编译规则

  1. 工厂函数调用:引用类型默认值作为工厂函数调用,确保独立性
  2. 数组默认值['one', 'two']在每次渲染时创建新数组
  3. 对象默认值:对象字面量同样遵循此模式,防止跨组件实例的引用共享

不支持的 withDefaults 用法

VuReact 明确不支持以下withDefaults用法,编译时会报错提示。

1. 未赋值给变量

withDefaults()必须赋值给一个变量(如const props = withDefaults(...)),不支持作为独立表达式调用:

<scriptsetuplang="ts">// 不支持的写法withDefaults(defineProps<Props>(),{msg:'hello'});</script>
<scriptsetuplang="ts">// 支持的写法constprops=withDefaults(defineProps<Props>(),{msg:'hello'});</script>

2. 第一个参数非defineProps()调用

withDefaults()的第一个参数必须是defineProps()的调用表达式,不支持传入其他表达式:

<scriptsetuplang="ts">// 不支持的写法constprops=withDefaults({msg:'hello'});</script>
<scriptsetuplang="ts">// 支持的写法constprops=withDefaults(defineProps<Props>(),{msg:'hello'});</script>

3. 第二个参数非对象字面量

withDefaults()的第二个参数必须是内联的对象字面量,不支持传入变量引用或其他表达式:

<scriptsetuplang="ts">// 不支持的写法constdefaults={msg:'hello'};constprops=withDefaults(defineProps<Props>(),defaults);</script>
<scriptsetuplang="ts">// 支持的写法constprops=withDefaults(defineProps<Props>(),{msg:'hello'});</script>

编译策略总结

VuReact 的withDefaults编译策略展示了完整的默认值转换能力

  1. Vue 宏分解:将withDefaults分解为类型保留、默认值合并、只读保证三部分
  2. 类型安全:Props 接口原样保留,不因默认值改变可选性
  3. 合并策略:通过useMemo合并原始 props 与默认值,确保性能优化
  4. 引用独立:引用类型默认值使用工厂函数,保证每次渲染独立实例

核心功能

  1. 自动合并:通过...vrProps+??空值合并实现默认值合并
  2. 只读保证useMemo<Readonly<Props>>确保 props 不可变
  3. 类型保留:接口定义原样保留,不影响外部类型约束
  4. 性能优化useMemo缓存合并结果,减少不必要的计算

注意事项

  1. 必须赋值给变量withDefaults()必须配合const props = ...使用
  2. 仅支持defineProps():第一个参数必须是defineProps()调用
  3. 仅支持对象字面量:第二个参数必须是内联对象字面量
  4. 引用类型用工厂:数组、对象等引用类型必须使用工厂函数形式

VuReact 的编译策略确保了从 Vue 到 React 的平滑迁移,开发者无需手动实现默认值合并逻辑。编译后的代码既保持了 Vue 的withDefaults语义和类型推导能力,又符合 React 的useMemo性能优化模式,让迁移后的应用保持完整的默认值处理能力。

综合示例对照

完整的withDefaults单文件组件编译前后对照,可参考以下代码:

  • Vue 代码(input.vue):
<scriptsetuplang="ts">// @vr-name: CompWithDefaultsinterfaceProps{msg?:string;count?:number;labels:string[];}constprops=withDefaults(defineProps<Props>(),{msg:'hello',count:42,labels:()=>['one','two'],});</script><template><div>{{ props.msg }} {{ props.count }}</div><ul><liv-for="value in props.labels":key="value">{{ value }}</li></ul></template>
  • VuReact 编译后 React 代码(output.tsx):
import{useMemo,memo}from'react';interfaceProps{msg?:string;count?:number;labels:string[];}exporttypeICompProps=Props;constCompWithDefaults=memo((vrProps:ICompProps)=>{/* from withDefaults */constprops=useMemo<Readonly<Props>>(()=>({...vrProps,msg:vrProps.msg??'hello',count:vrProps.count??42,labels:vrProps.labels??['one','two'],}),[vrProps]);return(<><div>{props.msg}{props.count}</div><ul>{props.labels.map(value=><li key={value}>{value}</li>)}</ul></>);});exportdefaultCompWithDefaults;

🔗 相关资源

  • VuReact 官方文档:语义编译对照总览
  • VuReact Runtime:useMemo
  • Github:https://github.com/vureact-js/core

📖 继续阅读

  • 上一篇:defineModel

✨ 如果你觉得本文对你理解 VuReact 有帮助,欢迎点赞、收藏、关注!