惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
P
Proofpoint News Feed
D
DataBreaches.Net
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
宝玉的分享
宝玉的分享
Recorded Future
Recorded Future
GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
C
Cisco Blogs
L
LangChain Blog
博客园 - 聂微东
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
量子位
AWS News Blog
AWS News Blog
爱范儿
爱范儿
Know Your Adversary
Know Your Adversary
F
Full Disclosure
MyScale Blog
MyScale Blog
Stack Overflow Blog
Stack Overflow Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Microsoft Azure Blog
Microsoft Azure Blog
S
Schneier on Security
Spread Privacy
Spread Privacy
P
Privacy International News Feed
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Latest news
Latest news
D
Docker
Scott Helme
Scott Helme
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
MongoDB | Blog
MongoDB | Blog
The Register - Security
The Register - Security
T
Tailwind CSS Blog
SecWiki News
SecWiki News
C
CERT Recently Published Vulnerability Notes
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security Affairs
G
GRAHAM CLULEY
Simon Willison's Weblog
Simon Willison's Weblog
Martin Fowler
Martin Fowler
I
InfoQ
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tenable Blog

Surmon.me

一人有限集团 你就是不敢 创造力是温柔的谎言 人类正在退出人类 AI 代替不了这样的你 脉冲点火背后的架构设计 基于 Cloudflare 生态的 AI Agent 实现 NodePress 支持用户登录了 从统计学习到通用智能 2025 投资报告:走慢的路 无依之地 会杀人的菩萨 无我不是共识 文化的积重与偏见 当下即安 科学的尽头是态度 无我不是 Egoless 信仰不因恐惧而存在 世间无解的矛与盾 先别急着做些什么 佛不需要你的皈依 真理的幻觉 两扇大门 造心里的浮屠 自胜者强 逻辑与智慧 真的相 快乐的秘密 只需愿意 是名体验 最深沉的梦 森林里倒下的树 现象与相 庸人自扰 开心就好吗 与原生家庭和解 两支毒箭 怎么自净其意 一尘不染 一片白云 让风穿膛而过 喝下去,然后闭嘴 活在当下 当纠结发生时 唯「我」独尊 一场把戏(时间) 一场把戏(二元对立) “我” 和 “我” 谁是众生? 船里没有人 玫瑰不需要说话 没有人能渡任何人 你我为轮,使之不再 当我们在谈论独立时 自我约束就是最好的自我接纳 从善与恶的表象出发 佛法不是心理学 别人眼中的你并不是你 高高山上走 祝你心想事成 祝你的噩梦早日发生 道是无情却有情 裙子只为自己而穿 不要盲目地评估自己 先别急着 “爱自己” 让生命欣然舞动 你无法复制乔布斯 符号不是目的 如果一件事发生了 每当我起心动念时 爱出者爱返 理解不是尊重的基础 在没有解决自己的问题之前 “知足常乐” 不是比较 逻辑是无法成为信仰的 买不到的自由 成为诵经者 伤口听不懂大道理 是立场让你不自由 - Unfreedom 天雨大不润无根之草 做自己的神 当心诱惑本身 牛洞冥思录 修罗启示录 让大脑自举 我更喜欢叫它无梦寺 存在主义也许不是解药 出南洋记 2022 的所有答复 没意义的表达 思考的记录 故宫暂行之幻想 极端的比较 解构的终极 舍利子是如何炼成的 心要野 佛教的偏见 文艺青年 我是动物 知行合一
React 与 Vue 的完美融合
Surmon · 2024-08-16 · via Surmon.me

React Hooks 的心智负担

在 React 中,状态管理一直是开发者关注的重点。React 的 useState 和 useEffect 虽然灵活,但当组件复杂度增加时,这种灵活性往往会变成负担。

最常见的,如依赖关系处理不当会导致 useEffect 中的副作用反复执行或者未按照预期执行,甚至引发内存泄漏。因为 useEffect 本质上是一个副作用管理工具,它要求开发者显式处理依赖关系,增加了代码的复杂性和维护难度,也就构成了我们所说的「心智负担」。即:总有一个地方是需要我特别注意的,不然就可能不符合预期

Vue + TypeScript 的类型挑战

得益于 mutable state 的天然属性,Vue 在处理响应式状态方面表现优异,但在结合 TypeScript 时,开发者常常需要面对类型定义的重复性工作。尤其是当项目中包含大量组件时,手动定义 propsemitsslots 和 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 实现了。

话不多说,码上见!

Ref

        
        

1234567891011121314151617

import React from 'react' import { useRef } from 'veact' export const Component: React.FC = () => { const count = useRef(0) const increment = () => { // 数据改变,组件 rerender count.value++ } return ( <div> <p>{count.value}</p> <button onClick={increment}>increment</button> </div> ) }

ShallowRef

        
        

1234567891011121314151617

import React from 'react' import { useShallowRef } from 'veact' export const Component: React.FC = () => { // 对应 Vue 中的 shallowRef const numbers = useShallowRef([1, 2, 3]) const resetNumbers = () => { numbers.value = [] } return ( <div> <p>{numbers.value.length}</p> <button onClick={resetNumbers}>resetNumbers</button> </div> ) }

Reactive

        
        

123456789101112131415161718192021222324252627

import React from 'react' import { useReactive } from 'veact' export const Component: React.FC = () => { // 数据的任何改变,都会导致 rerender 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

        
        

12345678910111213141516171819202122232425

import React from 'react' import { useReactive, useComputed } from 'veact' export const Component: React.FC = () => { const data = useReactive({ year: 3, count: 4, }) // Vue 中的 computed,类似于 React 的 useMemo,但不需要指定任何依赖 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

        
        

1234567891011121314151617181920212223242526272829303132

import React from 'react' import { useReactive, useWatch } from 'veact' export const Component: React.FC = () => { const data = useReactive({ count: 0, }) const incrementCount = () => { data.count++ } // Vue 中的 watch,监听数据对象的变化 useWatch(data, (newData) => { console.log('data changed', newData) }) // API 设计实现与 Vue 完全一致 useWatch( () => data.count, (newCount) => { console.log('count changed', newCount) }, ) return ( <div> <span>{data.count}</span> <button onClick={incrementCount}>incrementCount</button> </div> ) }

Reactivity

        
        

1234567891011121314151617181920

import React from 'react' import { ref, useReactivity } from 'veact' // 组件之外的一些响应式数据对象,可能来自于 global state,也可能来自第三方组件库 const countRef = ref(0) export const Component: React.FC = () => { // 通过 useReactivity() 转换后可以直接在组件内消费 const count = useReactivity(() => countRef) const increment = () => { count.value++ } return ( <div> <span>{count.value}</span> <button onClick={increment}>increment</button> </div> ) }

当然,最后还有 Vue 风格的生命周期。

        
        

123456789101112131415161718

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> }

如码所见,无论是定义响应式状态还是监听状态变化,Veact 都能让开发者在不牺牲灵活性的前提下,享受到更低的心智负担和更高的开发效率。并且 Veact 的数据系统与 React 自身的 state 系统是完全兼容的,并支持接近 100% 的互操作性。这也意味着,你并不需要以某种数据系统为基准对现有应用大改特改,可以从下一次的小页面、小组件开始尝试,如果对项目有益,再深入实践甚至推广到团队也是非常有价值的。

总的来说,Veact 是 Vue 与 React 最佳特性的结合体,它不仅简化了状态管理,还提供了强大的类型支持和直观的 API 设计,为前端开发者提供了一种全新的开发体验。

如果你厌倦了 React 中繁琐的副作用处理,或是困扰于 Vue 中的类型定义工作,那么 Veact 无疑是一个还不错的新选择。

GitHub 项目: https://github.com/veactjs/veact