[纯原创无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
				})
			}
		}
	})

}
相关推荐
TE-茶叶蛋3 小时前
React的合成事件(SyntheticEventt)
前端·javascript·react.js
不写八个9 小时前
Vue3.0教程005:watch监视ref定义的【基本类型】数据和【对象类型】数据
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=9 小时前
【Vue篇】组件的武林绝学:状态风暴下的乾坤挪移术
前端·javascript·vue.js
_xaboy10 小时前
开源表单设计器FcDesigner配置多语言教程
前端·vue.js·低代码·开源·表单设计器
郭尘帅66610 小时前
Vue3 父子组件传值, 跨组件传值,传函数
前端·javascript·vue.js
黑匣子~11 小时前
Electron + Vite + Vue 项目中的 IPC 通信三层封装实践
javascript·vue.js·electron
黑匣子~11 小时前
Electron + Vue 实现系统消息通知与点击跳转页面
javascript·vue.js·electron
_龙小鱼_12 小时前
Vue响应式系统演进与实现解析
前端·vue.js
云隙阳光i13 小时前
Vue3 中使用 provide/inject 实现跨层级组件传值失败的原因及解决方案
前端·javascript·vue.js