![图片[1]-React 与 Vue 的完美融合!Veact!-明恒博客](https://www.zym88.cn/wp-content/uploads/2024/08/20240816141007963-2024081606100776.png)
React Hooks 的心智负担
在 React 中,状态管理一直是开发者关注的重点。React 的 useState
和 useEffect
虽然灵活,但当组件复杂度增加时,这种灵活性往往会变成负担。
最常见的,如依赖关系处理不当会导致 useEffect
中的副作用反复执行或者未按照预期执行,甚至引发内存泄漏。因为 useEffect
本质上是一个副作用管理工具,它要求开发者显式处理依赖关系,增加了代码的复杂性和维护难度,也就构成了我们所说的「心智负担」,即:总有一个地方是需要我特别注意的,不然就可能不符合预期。
Vue + TypeScript 的类型挑战
得益于 mutable state 的天然属性,Vue 在处理响应式状态方面表现优异,但在结合 TypeScript 时,开发者常常需要面对类型定义的重复性工作。尤其是当项目中包含大量组件时,手动定义 props
、emits
、slots
和 attrs
的类型,繁琐、不自然,也不够明了。
有没有既要还要的?
有没有办法将两者的优点融合在一起?最好,它能够包含:
- 完美的 TypeScript + JSX 编码体验
- 完美的类型定义, 直接
export interface Props {}
一把嗦 - 完美的数据管理,再也不要关心
deps
这件事,把数据之间的依赖交给数据自己去组织
有!Veact 来了
Veact 将 Vue 的响应式系统引入 React,使得状态管理更加直观且易于维护。通过 Veact,开发者可以利用 Vue 的响应式系统,同时享受 React 的 JSX + TypeScript 强大类型支持。这种结合不仅减少了状态管理的复杂性,还避免了 React 中常见的副作用处理问题。通过 Veact,状态的变化是自动响应式的,无需手动处理依赖关系,这大大简化了开发者的工作。
你可能有疑问:听起来这和 mobx 之类的 state management 库有啥区别?重新造轮子吗?
由于 Veact 是完全基于 @vue/reactivity
实现的,所以 API 设计几乎与 Vue 完全一致,使用起来非常直观、自然,没有学习成本,维护成本也很低,毕竟大部分的核心工作已经由 Vue 实现了。
话不多说,码上见!
Lifecycle
import React from 'react'import { onMounted, onBeforeUnmount, onUpdated } from 'veact'export const Component: React.FC = () => {onMounted(() => {console.log('component mounted')})onUpdated(() => {console.log('component updated')})onBeforeUnmount(() => {console.log('component will unmount')})return <div>component</div>}import React from 'react' import { onMounted, onBeforeUnmount, onUpdated } from 'veact' export const Component: React.FC = () => { onMounted(() => { console.log('component mounted') }) onUpdated(() => { console.log('component updated') }) onBeforeUnmount(() => { console.log('component will unmount') }) return <div>component</div> }import React from 'react' import { onMounted, onBeforeUnmount, onUpdated } from 'veact' export const Component: React.FC = () => { onMounted(() => { console.log('component mounted') }) onUpdated(() => { console.log('component updated') }) onBeforeUnmount(() => { console.log('component will unmount') }) return <div>component</div> }
Ref
import React from 'react'import { useRef } from 'veact'export const Component: React.FC = () => {const count = useRef(0)const increment = () => {count.value++}return (<div><p>{count.value}</p><button onClick={increment}>increment</button></div>)}import React from 'react' import { useRef } from 'veact' export const Component: React.FC = () => { const count = useRef(0) const increment = () => { count.value++ } return ( <div> <p>{count.value}</p> <button onClick={increment}>increment</button> </div> ) }import React from 'react' import { useRef } from 'veact' export const Component: React.FC = () => { const count = useRef(0) const increment = () => { count.value++ } return ( <div> <p>{count.value}</p> <button onClick={increment}>increment</button> </div> ) }
ShallowRef
import React from 'react'import { useShallowRef } from 'veact'export const Component: React.FC = () => {const numbers = useShallowRef([1, 2, 3])const resetNumbers = () => {numbers.value = []}return (<div><p>{numbers.value.length}</p><button onClick={resetNumbers}>resetNumbers</button></div>)}import React from 'react' import { useShallowRef } from 'veact' export const Component: React.FC = () => { const numbers = useShallowRef([1, 2, 3]) const resetNumbers = () => { numbers.value = [] } return ( <div> <p>{numbers.value.length}</p> <button onClick={resetNumbers}>resetNumbers</button> </div> ) }import React from 'react' import { useShallowRef } from 'veact' export const Component: React.FC = () => { const numbers = useShallowRef([1, 2, 3]) const resetNumbers = () => { numbers.value = [] } return ( <div> <p>{numbers.value.length}</p> <button onClick={resetNumbers}>resetNumbers</button> </div> ) }
Reactive
import React from 'react'import { useReactive } from 'veact'export const Component: React.FC = () => {const data = useReactive({count: 10,nested: { count: 1 },})const incrementCount = () => {data.count++}const incrementNestedCount = () => {data.nested.count++}return (<div><p>{data.count}</p><p>{data.nested.count}</p><button onClick={incrementCount}>incrementCount</button><button onClick={incrementNestedCount}>incrementNestedCount</button></div>)}import React from 'react' import { useReactive } from 'veact' export const Component: React.FC = () => { const data = useReactive({ count: 10, nested: { count: 1 }, }) const incrementCount = () => { data.count++ } const incrementNestedCount = () => { data.nested.count++ } return ( <div> <p>{data.count}</p> <p>{data.nested.count}</p> <button onClick={incrementCount}>incrementCount</button> <button onClick={incrementNestedCount}>incrementNestedCount</button> </div> ) }import React from 'react' import { useReactive } from 'veact' export const Component: React.FC = () => { const data = useReactive({ count: 10, nested: { count: 1 }, }) const incrementCount = () => { data.count++ } const incrementNestedCount = () => { data.nested.count++ } return ( <div> <p>{data.count}</p> <p>{data.nested.count}</p> <button onClick={incrementCount}>incrementCount</button> <button onClick={incrementNestedCount}>incrementNestedCount</button> </div> ) }
Computed
import React from 'react'import { useReactive, useComputed } from 'veact'export const Component: React.FC = () => {const data = useReactive({year: 3,count: 4,})const total = useComputed(() => {return data.count * data.year})const incrementCount = () => {data.count++}return (<div><span>{total.value}</span><button onClick={incrementCount}>incrementCount</button></div>)}import React from 'react' import { useReactive, useComputed } from 'veact' export const Component: React.FC = () => { const data = useReactive({ year: 3, count: 4, }) const total = useComputed(() => { return data.count * data.year }) const incrementCount = () => { data.count++ } return ( <div> <span>{total.value}</span> <button onClick={incrementCount}>incrementCount</button> </div> ) }import React from 'react' import { useReactive, useComputed } from 'veact' export const Component: React.FC = () => { const data = useReactive({ year: 3, count: 4, }) const total = useComputed(() => { return data.count * data.year }) const incrementCount = () => { data.count++ } return ( <div> <span>{total.value}</span> <button onClick={incrementCount}>incrementCount</button> </div> ) }
Watch
import React from 'react'import { useReactive, useWatch } from 'veact'export const Component: React.FC = () => {const data = useReactive({count: 0,})const incrementCount = () => {data.count++}useWatch(data, (newData) => {console.log('data changed', newData)})useWatch(() => data.count,(newCount) => {console.log('count changed', newCount)},)return (<div><span>{data.count}</span><button onClick={incrementCount}>incrementCount</button></div>)}import React from 'react' import { useReactive, useWatch } from 'veact' export const Component: React.FC = () => { const data = useReactive({ count: 0, }) const incrementCount = () => { data.count++ } useWatch(data, (newData) => { console.log('data changed', newData) }) useWatch( () => data.count, (newCount) => { console.log('count changed', newCount) }, ) return ( <div> <span>{data.count}</span> <button onClick={incrementCount}>incrementCount</button> </div> ) }import React from 'react' import { useReactive, useWatch } from 'veact' export const Component: React.FC = () => { const data = useReactive({ count: 0, }) const incrementCount = () => { data.count++ } useWatch(data, (newData) => { console.log('data changed', newData) }) useWatch( () => data.count, (newCount) => { console.log('count changed', newCount) }, ) return ( <div> <span>{data.count}</span> <button onClick={incrementCount}>incrementCount</button> </div> ) }
EffectScope
import React from 'react'import { watch, useRef, useEffectScope, onScopeDispose } from 'veact'export const Component: React.FC = () => {const scope = useEffectScope()const counter = useRef(0)const incrementCounter = () => {counter.value++}scope.run(() => {const doubled = computed(() => counter.value * 2)watch(doubled, (newValue) => console.log(newValue))watchEffect(() => console.log('doubled: ', doubled.value))onScopeDispose(() => console.log('effect scope is stopped'))})return (<div><span>{counter.value}</span><button onClick={incrementCounter}>incrementCounter</button><button onClick={() => scope.pause()}>pause Scope</button><button onClick={() => scope.resume()}>resume Scope</button><button onClick={() => scope.stop()}>stop Scope</button></div>)}import React from 'react' import { watch, useRef, useEffectScope, onScopeDispose } from 'veact' export const Component: React.FC = () => { const scope = useEffectScope() const counter = useRef(0) const incrementCounter = () => { counter.value++ } scope.run(() => { const doubled = computed(() => counter.value * 2) watch(doubled, (newValue) => console.log(newValue)) watchEffect(() => console.log('doubled: ', doubled.value)) onScopeDispose(() => console.log('effect scope is stopped')) }) return ( <div> <span>{counter.value}</span> <button onClick={incrementCounter}>incrementCounter</button> <button onClick={() => scope.pause()}>pause Scope</button> <button onClick={() => scope.resume()}>resume Scope</button> <button onClick={() => scope.stop()}>stop Scope</button> </div> ) }import React from 'react' import { watch, useRef, useEffectScope, onScopeDispose } from 'veact' export const Component: React.FC = () => { const scope = useEffectScope() const counter = useRef(0) const incrementCounter = () => { counter.value++ } scope.run(() => { const doubled = computed(() => counter.value * 2) watch(doubled, (newValue) => console.log(newValue)) watchEffect(() => console.log('doubled: ', doubled.value)) onScopeDispose(() => console.log('effect scope is stopped')) }) return ( <div> <span>{counter.value}</span> <button onClick={incrementCounter}>incrementCounter</button> <button onClick={() => scope.pause()}>pause Scope</button> <button onClick={() => scope.resume()}>resume Scope</button> <button onClick={() => scope.stop()}>stop Scope</button> </div> ) }
Reactivity
将一些尚未封装在Hooks中的 “原始 Vue “数据转换为反应钩子数据,以确保组件内的适当反应性。
import React from 'react'import { ref, useReactivity } from 'veact'// ref data without hooksconst countRef = ref(0)export const Component: React.FC = () => {// to reactivity hookconst count = useReactivity(() => countRef)const increment = () => {count.value++}return (<div><span>{count.value}</span><button onClick={increment}>increment</button></div>)}import React from 'react' import { ref, useReactivity } from 'veact' // ref data without hooks const countRef = ref(0) export const Component: React.FC = () => { // to reactivity hook const count = useReactivity(() => countRef) const increment = () => { count.value++ } return ( <div> <span>{count.value}</span> <button onClick={increment}>increment</button> </div> ) }import React from 'react' import { ref, useReactivity } from 'veact' // ref data without hooks const countRef = ref(0) export const Component: React.FC = () => { // to reactivity hook const count = useReactivity(() => countRef) const increment = () => { count.value++ } return ( <div> <span>{count.value}</span> <button onClick={increment}>increment</button> </div> ) }
如码所见,无论是定义响应式状态还是监听状态变化,Veact 都能让开发者在不牺牲灵活性的前提下,享受到更低的心智负担和更高的开发效率。并且 Veact 的数据系统与 React 自身的 state 系统是完全兼容的,并支持接近 100% 的互操作性。这也意味着,你并不需要以某种数据系统为基准对现有应用大改特改,可以从下一次的小页面、小组件开始尝试,如果对项目有益,再深入实践甚至推广到团队也是非常有价值的。
总的来说,Veact 是 Vue 与 React 最佳特性的结合体,它不仅简化了状态管理,还提供了强大的类型支持和直观的 API 设计,为前端开发者提供了一种全新的开发体验。
如果你厌倦了 React 中繁琐的副作用处理,或是困扰于 Vue 中的类型定义工作,那么 Veact 无疑是一个还不错的新选择。
4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报。
6 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
暂无评论内容