VuReact 已于近日完成对 Vue 3.4+ defineModel 宏的完整编译支持。开发者现在可以在 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):
<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 产物:
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 被分解为三部分 —— prop 类型声明与事件回调声明被映射到 IChildProps 类型中,运行时响应式通过 useVRef + useUpdated 实现。模板中的 v-model 则被编译为 React 受控组件的 value + onChange 模式。
本次支持的 defineModel 能力包括:
-
基础双向绑定:defineModel<string>() 编译为 prop 类型声明 + onUpdateXxx 事件回调 + useVRef 运行时响应式
-
自定义 prop 名称:defineModel<string>('state') 支持指定 prop 名称,父组件通过 v-model:state 使用
-
类型与默认值:支持 type、default、required 选项,required: true 在类型定义中转为必填,default 通过 ?? 空值合并实现
-
模板 v-model 绑定:编译为 React 受控组件的 value + onChange 模式
暂不支持的 defineModel 用法:
上述不支持的场景,建议使用标准 defineModel 写法或直接使用 useVRef 自行实现自定义逻辑。
VuReact 是一套面向 Vue 迁移 React 与混合开发的完整解决方案,将 Vue 3 SFCs・Scripts・Styles 完整转为纯 React(非运行时桥接)组件的 AST 编译器,采用语义级编译路线,产物为纯 React 代码,不依赖 Vue 运行时。目前已完成 defineProps、defineEmits、defineExpose、defineModel 等核心宏的语义映射,以及 ref、computed、watch、scoped style 等 Vue 特性的完整适配。
详情可查阅:
VuReact GitHub:https://github.com/vureact-js/core(欢迎 Star ⭐~开源不易)
defineModel 编译对照:https://vureact.top/guide/semantic-comparison/script/define-model.html