来试试用 react 的写法写 vue

前言

我在 vue2 里面用 react 的写法写了很久的 vue,现在想想有没有机会在 vue3 里面复刻一下,于是试了试,确实可以,经过一些魔法和限制,我们可以在 vue 里面享受到和 react 一样优秀的 typescript 体验,并且有着 vue 保底的性能优势。

这种写法最大的优势在于:

  • 编译足够简单,你可以选用任意支持 jsx 构建的编译器,比如 swc、esbuild、tsc 等等
  • 类型系统足够简单
  • 概念简单清晰
  • 编写的代码是完全的 typescript,没有任何编译器魔法

劣势在于:

  • 性能,你无法使用任何 vue-compiler 带来的优化,如果具有强烈性能要求的场景,需要你手工优化
  • 屏蔽了绝大部分 vue sfc 的语法糖,你只能使用完全符合 typescript 中定义的语法

项目地址位于: github.com/iceprosurfa... ,喜欢这个项目的话可以帮忙点个 star ~

如果你只是希望体验一下功能的话可以直接前往 REPL 体验, REPL 尚未支持样式,你可以选择使用 unocss 代替(以内置,使用 class 提供支持)。

安装

如果是一个全新的项目,那么你可以使用 vite 默认的 vue 配置,随后使用 npm 安装即可:

bash 复制代码
npm install @vueireact/core

下面你只需要简单配置一下 tsconfig 即可使用:

json 复制代码
{ 
  "compilerOptions": { 
    "jsx": "react-jsx", 
    "jsxImportSource": "@vueireact/core" 
  }
}

随后你可以选择移除 vue plugin,因为这个系统是基于 runtime 实现的,并不需要 vue compiler

ts 复制代码
// vite.config.ts
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [], // 从这里移除 vue()
})

使用 & 概念

如何声明一个组件

在 vueireact 中,我们的组件只包含两个组成部分,函数的 setup 声明区域返回值 render function

ts 复制代码
function App (
  // 这里是 props
  props,
  // context 目前只支持了 expose
  context
) {
  // 相当于 setup

  // 这里返回的 render
  return () => ...
}

// 如果需要将组件暴露给 vue 体系使用,那么你需要使用 toVue 或是 toVues
const components = toVues({
  HelloWorld
})
// 或是这样
const HelloWorld = toVue(HelloWorld)

我们以 vue 的 hello world 为例子:

tsx 复制代码
import { ref } from 'vue'
function HelloWorld () {
  const message = ref('Hello World!')
  return () => <h1>{ message.value }</h1>
}

function App() {
  return () => <HelloWrold />
}

这样就完成了一个 hello world 的组件声明和使用了。

一个更加进阶一点的例子

下面我们举一个更加进阶一点的例子,比如一个带插槽渲染的泛型组件:

tsx 复制代码
import { ref } from 'vue'
import { toVue } from '@vueireact/core'
// 你可以像正常的函数一样,随意的声明泛型
function GenericComponent<T>(props: {
  list: T[]
  onListChange: (list: T[]) => void
  // 你可以声明具名插槽要求传入的类型匹配你的要求
  children: {
    item: (item: T, index: number) => JSX.Element;
  }
}) {
  return () => (
    <div>
      <h1>{
        props.list.map((item, index) => (props.children.item(item, index)))
      }</h1>
    </div>
  )
}

function App() {
  const list = ref([1, 2, 3]);
  function addOneToListItem(index: number) {
    const current = list.value[index]
    list.value.splice(index, 1, current + 1)

  }
  function addItem() {
    list.value.push(list.value.length + 1)
  }
  return () => (
    <div>
      {/* 这里组件会自动识别泛型,并约束,如果需要手工标注则可以这样写: <GenericComponent<string> */}
      <GenericComponent
        list={list.value}
        onListChange={(v) => list.value = v}
      >
        {
          {
            item: (item, index) => <div key={`item` + index} onClick={() => addOneToListItem(index)}>{item}</div>
          }
        }
      </GenericComponent>
      <button onClick={addItem}>Add</button>
    </div>
  )
}

ref

调用组件方法可以通过 defineExpose 以及 useRef 配合来使用,他们是强类型匹配的,可以有效减少错误。

tsx 复制代码
import { toVue, defineExpose, useRef } from '@vueireact/core'
function RefComponent(props: {},
  ctx: {
    // 使用 expose 定义会存在哪些方法
    expose: {
      refresh: () => void
    }
  }
) {
  defineExpose(ctx, {
    // 定义需要暴露的方法,不建议对外暴露属性,如果需要暴露的应该使用 getFunction 或将依赖倒置到顶层
    // defineExpose 内部使用 expose 来对外暴露属性,其效果和 vue 的 expose 完全一致,此方法仅为语法糖
    refresh: () => alert('ctx')
  })
  return () => (<div/>)
}

function App() {
  const refComponent = useRef(RefComponent)
  function refresh() {
    refComponent.value?.refresh();
    // 点击后会 alert 
  }
  return () => (
    <div>
      <RefComponent ref={refComponent}></RefComponent>
      <button onClick={refresh} >refresh</button>
    </div>
  )
}

export default toVue(App)

结语

在 vue 中使用 react 的写法是完全可行的,至少我在 vue2 中使用并上线了超过 20万行代码,但是 vue2 版本的实现方式和 vue3 版本有比较大差异,vue3 版本的代码尚未经过检验,请谨慎使用。

其他功能可以查看 官方文档

相关推荐
滕青山1 天前
在线PDF拆分工具核心JS实现
前端·javascript·vue.js
光影少年1 天前
前端在页面渲染优化和组件优化经验?
前端·vue.js·react.js·前端框架
李白的天不白1 天前
VUE依赖配置问题
前端·javascript·vue.js
小智社群1 天前
获取贝壳新房列表
前端·javascript·vue.js
一 乐1 天前
茶叶商城|基于springboot + vue茶叶商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·茶叶商城系统
吴声子夜歌1 天前
Vue3——Pinia状态管理
javascript·vue.js·pinia
追风筝的人er2 天前
SpringBoot+Vue3 企业考勤如何处理法定假期?节假日方案、调休补班与工作日判断链路拆解
前端·vue.js·后端
编程老船长2 天前
解决不同项目需要不同 Node.js 版本的问题
前端·vue.js
xiaogg36782 天前
spring oauth2 单点登录
java·vue.js·spring
前端那点事2 天前
Vue前端SEO优化全攻略(实操落地版,新手也能上手)
前端·vue.js