游乐游手机版
首页/前端开发/文章详情

Vue withDefaults转React时,VuReact如何处理?

时间:2026-07-16 06:31
VuReact将Vue3单文件组件编译为纯React代码,其withDefaults转换策略通过useMemo和空值合并运算符??实现默认值合并,保留Props接口类型与只读性,引用类型默认值使用工厂函数确保实例独立。该工具不支持未赋值变量、非defineProps()参数或非对象字面量写法。

VuReact 这个工具,说白了就是为 Vue 迁移到 React 量身定做的智能编译器。它能把 Vue 3 的单文件组件(包括脚本、样式)完整转换成纯 React 代码,而不是搞什么运行时桥接。重点在于,它覆盖了

  • VuReact 编译后 React 代码:
 复制代码import { useMemo, memo } from 'react';interface Props {
  msg?: string;
  count?: number;
  labels: string[];
}export type ICompProps = Props;const Input = memo((vrProps: ICompProps) => {
  /* from withDefaults */
  const props = 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> 确保返回的 props 对象是只读的,跟 Vue 中 withDefaults 的运行时不可变性保持一致。

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


基本类型默认值

对于 stringnumber 这些基本类型的默认值,VuReact 直接上 ?? 空值合并运算符:

  • Vue 代码:
 复制代码
  • VuReact 编译后 React 代码:
 复制代码const props = 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 代码:
 复制代码
  • VuReact 编译后 React 代码:
 复制代码const props = useMemo<Readonly<Props>>(() => ({
  ...vrProps,
  labels: vrProps.labels ?? ['one', 'two'],
}), [vrProps]);

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

编译规则

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

不支持的 withDefaults 用法

VuReact 明确不支持以下 withDefaults 用法,编译时直接报错。

1. 未赋值给变量

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

 复制代码<script setup lang="ts">
// 不支持的写法
withDefaults(defineProps<Props>(), { msg: 'hello' });
script>
 复制代码<script setup lang="ts">
// 支持的写法
const props = withDefaults(defineProps<Props>(), { msg: 'hello' });
script>

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

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

 复制代码<script setup lang="ts">
// 不支持的写法
const props = withDefaults({ msg: 'hello' });
script>
 复制代码<script setup lang="ts">
// 支持的写法
const props = withDefaults(defineProps<Props>(), { msg: 'hello' });
script>

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

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

 复制代码<script setup lang="ts">
// 不支持的写法
const defaults = { msg: 'hello' };
const props = withDefaults(defineProps<Props>(), defaults);
script>
 复制代码<script setup lang="ts">
// 支持的写法
const props = withDefaults(defineProps<Props>(), { msg: 'hello' });
script>

编译策略总结

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

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

核心功能

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

注意事项

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

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

综合示例对照

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

  • Vue 代码(input.vue):
 复制代码<script setup lang="ts">
// @vr-name: CompWithDefaultsinterface Props {
  msg?: string;
  count?: number;
  labels: string[];
}const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  count: 42,
  labels: () => ['one', 'two'],
});
script><template>
  <div>{{ props.msg }} {{ props.count }}div>
  <ul>
    <li v-for="value in props.labels" :key="value">{{ value }}li>
  ul>
template>
  • VuReact 编译后 React 代码(output.tsx):
 复制代码import { useMemo, memo } from 'react';interface Props {
  msg?: string;
  count?: number;
  labels: string[];
}export type ICompProps = Props;const CompWithDefaults = memo((vrProps: ICompProps) => {
  /* from withDefaults */
  const props = 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>
    
  );
});export default CompWithDefaults;

相关资源


来源:https://juejin.cn/post/7657197094155321344
上一篇Vue3+Vite+TS+Pinia生命周期详解第八章 下一篇React contentEditable元素光标错位问题修复方法
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
JavaScript动态加载与执行脚本的完整使用方法详解
前端开发 · 2026-07-17

JavaScript动态加载与执行脚本的完整使用方法详解

动态加载JavaScript脚本主要有三种方式:通过document createElement插入标签兼容性最好;import()支持按需加载ES模块并返回Promise;eval或Function构造器适用于执行代码字符串但风险较高。使用时需注意避免重复加载、处理超时及服务端渲染环境。

箭头函数多行逻辑的书写优化
前端开发 · 2026-07-17

箭头函数多行逻辑的书写优化

箭头函数多行逻辑需用花括号包裹并显式return,否则返回undefined;单行仅限一个表达式自动返回;返回对象字面量必须加小括号;复杂逻辑应拆分为独立函数,避免硬塞导致代码混乱。

如何设计JavaScript函数缓存防止内存无限增长
前端开发 · 2026-07-17

如何设计JavaScript函数缓存防止内存无限增长

防止函数缓存导致内存无限增长,需主动控制容量和寿命。采用LRU策略自动淘汰闲置条目,设定TTL防止脏数据长期驻留,优化键生成避免冗余堆积,并提供手动清理接口配合业务生命周期。

JavaScript布尔值转换核心逻辑详解
前端开发 · 2026-07-17

JavaScript布尔值转换核心逻辑详解

JavaScript布尔转换遵循明确的真值与假值规则,仅有6个假值:false、0、空字符串、null、undefined、NaN,其余所有值包括空数组、空对象均为真值。显式转换推荐Boolean(),隐式转换常见于条件判断与逻辑运算,需注意??与||的区别。

如何利用Performance API识别长任务来源的完整方法详解
前端开发 · 2026-07-17

如何利用Performance API识别长任务来源的完整方法详解

利用性能API识别长任务来源,需结合时间锚点、开发者工具验证和主动埋点。通过性能观察者捕获基础信息,使用性能标记缩小范围,借助Chrome开发者工具定位代码行,最后通过主动埋点验证,将长任务映射到具体代码段。