🎉 VuReact 1.9.0 发布,支持 Vue 3.4 defineModel 编译到 React

VuReact 已于近日完成对 Vue 3.4+ defineModel 宏的完整编译支持 #56。开发者现在可以在 Vue 源码中直接使用 defineModel 声明 v-model 双向绑定,VuReact 会将其编译为标准、可维护的 React 代码。

defineModel 是 Vue 3.4 中正式发布的编译器宏,用于简化 v-model 双向绑定的声明。VuReact 将其编译为 useVRef + useUpdated 的组合:useVRef 将 prop 值转为响应式 ref,useUpdated 在值变化时自动触发 onUpdate:xxx 回调通知父组件。组件内直接修改 .value 即可触发父组件更新,与 Vue 开发体验完全一致。

代码示例

Vue 源码(使用 defineModel):

html 复制代码
<script setup lang="ts">
// 声明 "state" prop,由父组件通过 v-model:state 使用
const state = defineModel<string>('state');

// 声明带选项的 "modelValue" prop,由父组件通过 v-model 使用
const modelValue = defineModel({ default: 'xxx' });

// 声明带选项的 "count" prop,由父组件通过 v-model:count 使用
const count = defineModel<number>('count', {
  type: Number,
  default: 0,
  required: true,
});

const update = () => {
  state.value = 'hello';
  count.value++;
};
</script>

<template>
  <input v-model="modelValue" />
  <div>Parent bound v-model is: {{ count }}</div>
  <button @click="update">Increment</button>
</template>

VuReact 编译后的 React 产物:

ts 复制代码
import { useCallback, memo } from 'react';
import { useVRef, useUpdated } from '@vureact/runtime-core';

export type IChildProps = {
  state?: string;
  modelValue?: string;
  count: number;
} & {
  onUpdateState?: (arg: string) => void;
  onUpdateModelValue?: (arg: string) => void;
  onUpdateCount?: (arg: number) => void;
};

const Child = memo((props: IChildProps) => {
  const state = useVRef<string>(props.state);
  const modelValue = useVRef<string>(props.modelValue ?? 'xxx');
  const count = useVRef<number>(props.count ?? 0);

  const update = useCallback(() => {
    state.value = 'hello';
    count.value++;
  }, [state.value, count.value]);

  useUpdated(() => {
    props.onUpdateState?.(state.value);
  }, [state.value]);

  useUpdated(() => {
    props.onUpdateModelValue?.(modelValue.value);
  }, [modelValue.value]);

  useUpdated(() => {
    props.onUpdateCount?.(count.value);
  }, [count.value]);

  return (
    <>
      <input
        value={modelValue}
        onChange={(e) => {
          modelValue.value = e.target.value;
        }}
      />
      <div>Parent bound v-model is:{count.value}</div>
      <button onClick={update}>Increment</button>
    </>
  );
});

export default Child;

从示例可以看到:Vue 的 defineModel 被分解为三部分:

  1. prop 类型声明IChildProps 类型中的非事件字段(state?modelValue?count
  2. 事件回调声明IChildProps 类型中的 onUpdateXxx 事件回调字段
  3. 运行时响应式useVRef 将 prop 初始值转为响应式 ref,useUpdated 监听值变化并自动调用父组件传入的回调

模板中的 v-model 则被编译为 React 受控组件的 value + onChange 模式。

本次支持的 defineModel 能力

能力 说明
基础双向绑定 defineModel<string>() 编译为 prop 类型声明 + onUpdateXxx 事件回调 + useVRef 运行时响应式
自定义 prop 名称 defineModel<string>('state') 支持指定 prop 名称,父组件通过 v-model:state 使用
类型与默认值 支持 typedefaultrequired 选项,required: true 在类型定义中转为必填,default 通过 ?? 空值合并实现
模板 v-model 绑定 编译为 React 受控组件的 value + onChange 模式

暂不支持的 defineModel 用法

用法 说明
const [model, modifiers] = defineModel() 返回值数组解构(Vue 3.4+ 实验特性)
get / set 自定义存取器 自定义 prop 读写逻辑
validator 验证函数 prop 值验证

上述不支持的场景,建议使用标准 defineModel 写法或直接使用 useVRef 自行实现自定义逻辑。

关于 VuReact

VuReact 是一个将 Vue 3 单文件组件编译为纯 React 组件的 AST 编译器,采用语义级编译路线,产物为纯 React 代码,不依赖 Vue 运行时。目前已完成 definePropsdefineEmitsdefineExposedefineModel 等核心宏的语义映射,以及 refcomputedwatchscoped style 等 Vue 特性的完整适配。

相关链接:

写在最后

defineModel 是 Vue 3.4 引入的重要特性,VuReact 完成对其的编译支持,意味着 Vue 开发者可以在迁移到 React 时继续使用这套熟悉的双向绑定写法,不必手动改写为 useState + props.onChange 的模式。

如果你正在经历 Vue → React 的迁移,欢迎在评论区分享你的场景和经验,也欢迎给 VuReact 点个 Star 支持开源~

扩展阅读:

相关推荐
spmcor2 小时前
React 架构师之路:Next.js 全栈革命(第八篇)
前端·react.js
英勇无比的消炎药2 小时前
TinyRobot 源码深度分析:OpenTiny 的 AI 对话组件库
前端·vue.js·github
假如让我当三天老蒯2 小时前
React基础、进阶(学习用)
前端·react.js·面试
spmcor2 小时前
为什么页面越用越卡?——React组件内存泄漏的排查与修复
react.js
swipe15 小时前
从 0 到 1 实现大文件上传:分片、秒传、断点续传、暂停、重试与服务端合并
前端·javascript·面试
天蓝色的鱼鱼17 小时前
React Router v8 来了:react-router-dom 没了,老项目该怎么迁移?
前端·react.js
阳火锅19 小时前
😭测试小姐姐终于不骂我了!这个提BUG神器太香了...
前端·javascript·面试
行者全栈架构师21 小时前
UniApp集成vk-uview-ui组件库详解:打造高效UI开发体验
前端·vue.js
林希_Rachel_傻希希21 小时前
js里面的proxy理解。以及vue3响应式数据设计底层
前端·javascript·面试