[纯原创无Ai] 我把React调教成vue的模样了

为什么我要这么做?

本人一个重度vue患者,最近想学习react,但是总是感觉浑身不舒服,比如不理解为什么管理状态需要调用React.useState,还要解构一个真数据一个设置器函数。比如为什么React没有像Vue那样导出好几个生命周期函数,而是要在React.useEffect里面找到合适的调用时机。React给我的一整个感觉就是:不方便,不顺手,找不到逻辑该写哪,很让初学者挠头。估计是因为我用了好几年的vue,被宠坏了,没办法改过来

于是!

我开始对React大刀阔斧,想办法把它调教成我熟悉的风格,一开始是只有两个生命周期函数,用了两天,感觉对react的其他部分也有点意见,既然函数名都换了,那干脆直接定义一个useVue得了,传入一个类似于vue的配置对象,直接获得媲美于vue的开发习惯

封装的useVue代码

js 复制代码
import React from "react";
import * as immer from 'immer';

function onMounted(cb) {
  React.useEffect(() => {
    cb()
  }, []);
}

function onBeforeUnmount(cb) {
  React.useEffect(() => {
    return cb
  }, []);
}

function useCustomReactive(originalData) {
  let [data, setDataHandler] = React.useState(originalData)
  function setData(draftchange) {
    setDataHandler(immer.produce(data, draftchange))
  }
  return [data, setData]
}


/**
 * 使用 Vue 风格的配置对象
 * @param {Object} vm - vm配置对象,必传
 * @param {返回值是JSX组件的函数} vm.template - 必需的模板函数,用于渲染内容 通过 `<p> {this.$data.xxx} </p>` 访问数据
 * @param {初始化数据对象|返回一个对象的函数} [vm.data] - 数据对象或返回数据对象的函数 通过 `this.$setData(draft=>{ draft.xxx = this.$data.xxx+1 })` 设置数据。
 * @param {对象} [vm.methods] - 方法配置 通过 `this.$methods.func_name()` 调用。
 * @param {对象} [vm.computed] - 计算属性对象 通过 `<p> {this.$computed.xxx} </p>` 访问数据
 * @param {生命周期} [vm.mounted] - 挂载完成时的回调函数
 * @param {生命周期} [vm.beforeUnmount] - 卸载前的回调函数
 * @returns {React组件} 模板函数的返回值
 */
export function useVue(vm) {
  if (vm.data) {
    if (typeof vm.data === 'function') {
      vm.data = vm.data()
    }
    let [$data, $setData] = useCustomReactive(vm.data)
    vm.$data = $data
    vm.$setData = $setData
  }
  if (vm.methods) {
    for (let functionName in vm.methods) {
      vm.methods[functionName] = vm.methods[functionName].bind(vm)
    }
    vm.$methods = vm.methods
  }
  if (vm.computed) {
    for (let propertyName in vm.computed) {
      vm.computed[propertyName] = vm.computed[propertyName].bind(vm)
    }
    vm.$computed = vm.computed
  }

  if (vm.mounted) onMounted(vm.mounted.bind(vm))
  if (vm.beforeUnmount) onBeforeUnmount(vm.beforeUnmount.bind(vm))

  return vm.template()
}

使用示例

jsx"use 复制代码
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
import { useVue } from '@/app/utils.js'


export default function MyComponents() {

	return useVue({

		template() {
			return <>
				<Button onClick={this.$methods.toggle_show_load_button}>显示或隐藏加载按钮</Button>
				<Button onClick={this.$methods.init_list} style={{ 'display': this.$data.show_button ? 'block' : 'none' }}>开始加载</Button>
				<br />
				<ul>
					{this.$data.list.map(item => <li key={item.key}>{item.value}</li>)}
				</ul>
				<br />
				<ol>
					{this.$computed.all_chunk().map(item => <li key={item}>{item}</li>)}
				</ol>
			</>
		},

		data() {
			return {
				show_button: true,
				list: [],
				chunk_1: [1, 2, 3, 4, 5],
				chunk_2: [6, 7, 8],
			}
		},

		computed: {
			all_chunk() {
				return [...this.$data.chunk_1, ...this.$data.chunk_2]
			}
		},

		mounted() {
			this.$methods.toggle_show_load_button()
		},

		methods: {
			init_list() {
				setTimeout(() => {
					this.$setData(draft => {
						draft.list = (new Array(10)).fill(0).map((_, key) => ({ value: Math.random(), key }))
						draft.chunk_1 = this.$data.chunk_1.slice(0,3)
					})
				}, 2000) // 模拟请求,两秒后加载出数据
			},
			toggle_show_load_button() {
				this.$setData(draft => {
					console.log(this.$data.show_button)
					draft.show_button = !this.$data.show_button
				})
			}
		}
	})

}
相关推荐
一 乐2 小时前
点餐|智能点餐系统|基于java+ Springboot的动端的点餐系统小程序(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·小程序·论文
久爱@勿忘5 小时前
vue下载项目内静态文件
前端·javascript·vue.js
摇滚侠8 小时前
Vue 项目实战《尚医通》,医院详情菜单与子路由,笔记17
前端·vue.js·笔记
有来技术8 小时前
vite-plugin-vue-mcp:在 Vue 3 + Vite 中启用 MCP,让 AI 理解并调试你的应用
前端·vue.js·人工智能
鹏北海8 小时前
Vue 3 超强二维码识别:多区域/多尺度扫描 + 高级图像处理
前端·javascript·vue.js
骑自行车的码农8 小时前
React SSR 技术实现原理
算法·react.js
网络点点滴9 小时前
watch监视-ref基本类型数据
前端·javascript·vue.js
西洼工作室9 小时前
前端接口安全与性能优化实战
前端·vue.js·安全·axios
Crystal32811 小时前
App端用户每日弹出签到弹窗如何实现?(uniapp+Vue)
前端·vue.js
molly cheung11 小时前
Vue3:watch与watchEffect的异同
vue.js·watch·store·watcheffect