网易首页 > 网易号 > 正文 申请入驻

Solid.js 就是我理想中的 React

0
分享至

作者 | Nick Scialli

译者 | 王强

策划 | 闫园园

我大约在三年前开始在工作中使用 React。巧合的是,当时正好是 React Hooks 出来的时候。我当时的项目代码库有很多类组件,总让我觉得很笨重。

我们来看看下面的例子:一个每秒递增一次的计数器。


class Counter extends React.Component {constructor() {super();this.state = { count: 0 };this.increment = this.increment.bind(this);increment() {this.setState({ count: this.state.count + 1 });componentDidMount() {setInterval(() => {this.increment();}, 1000);render() {return

The count is: {this.state.count}

对于一个自动递增的计数器来说要写这么多代码可不算少。更多的模板和仪式意味着出错的可能性更大,开发体验也更差。

Hooks 很漂亮,但是容易出错

当 hooks 出现的时候我非常兴奋。我的计数器可以简化为以下写法:


function Counter() {const [count, setCount] = useState(0);useEffect(() => {setInterval(() => {setCount(count + 1);}, 1000);}, []);return

The count is: {count}div>;

等等,这其实是不对的。我们的 useEffect hook 在 count 周围有一个陈旧闭包,因为我们没有把 count 包含在 useEffect 依赖数组中。从依赖数组中省略变量是 React hooks 的一个常见错误,如果你忘记了,有一些 linting 规则会警告你的。

我稍后会回到这个问题上。现在,我们把缺少的 count 变量添加到依赖数组中:


function Counter() {const [count, setCount] = useState(0);useEffect(() => {setInterval(() => {setCount(count + 1);}, 1000);}, [count]);return

The count is: {count}div>;

但现在我们遇到了另一个问题,看看应用程序的运行效果:

精通 React 的人们可能知道发生了什么事情,因为你每天都在与这种问题作斗争:我们创建了太多的间隔(每次重新运行效果时都会创建一个新间隔,也就是每次我们增加 count 时间隔都会增加)。可以通过几种方式来解决这个问题:

  • 从清除间隔的 useEffect hook 返回一个清理函数

  • 使用 setTimeout 代替 setInterval(还是要使用清理函数)

  • 使用 setCount 的函数形式来避免直接引用当前值

事实上哪种办法都行得通。我们在这里实现最后一个选项:


function Counter() {const [count, setCount] = useState(0);useEffect(() => {setInterval(() => {setCount((count) => count + 1);}, 1000);}, []);return

The count is: {count}div>;

我们的计数器修好了!由于依赖数组中没有任何内容,因此我们只创建了一个间隔。由于我们为计数设置器使用了回调函数,因此永远不会在 count 变量上有陈旧闭包。

这是一个人为做出来的例子,但除非你已经使用 React 一段时间,否则它仍然很令人困惑。我们中有许多人每天都会遇到更复杂的情况,即使是最有经验的 React 开发人员也会为之头痛不已。

假的响应性

我思考了很多关于 hooks 的事情,想知道为什么它们感觉不太对劲。结果我通过探索 Solid.js 找到了答案。

React hooks 的问题在于 React 并不是真正的响应式设计。如果 linter 知道一个效果(或回调或 memo)hook 何时缺少依赖项,那么为什么框架不能自动检测依赖项并对这些更改做出响应呢?

深入研究 Solid.js

关于 Solid,首先要注意的是它没有尝试重新发明轮子:它看起来很像 React,因为 React 有一些显眼的模式:单向、自上而下的状态;JSX;组件驱动的架构。

如果我们用 Solid 重写 Counter 组件,会这样开始:


function Counter() {const [count, setCount] = createSignal(0);return

The count is: {count()}div>;

到目前为止我们看到了一个很大的不同点:count 是一个函数。这称为访问器(accessor),它是 Solid 工作机制的重要组成部分。当然,我们这里没有关于按间隔递增 count 的内容,所以下面把它添加进去:


function Counter() {const [count, setCount] = createSignal(0);setInterval(() => {setCount(count() + 1);}, 1000);return

The count is: {count()}div>;

这肯定行不通,对吧?每次组件渲染时不会设置新的间隔吗?

没有。它就这么正常运行了。

但为什么会这样?好吧,事实证明 Solid 不需要重新运行 Counter 函数来重渲染新的计数。事实上,它根本不需要重新运行 Counter 函数。如果我们在 Counter 函数中添加一个 console.log 语句,就会看到它只运行一次。


function Counter() {const [count, setCount] = createSignal(0);setInterval(() => {setCount(count() + 1);}, 1000);console.log('The Counter function was called!');return

The count is: {count()}div>;

在我们的控制台中,只有一个孤独的日志语句:


"The Counter function was called!"

"The Counter function was called!"在 Solid 中,除非我们明确要求,否则代码不会多次运行。

但是 hooks 呢?

于是我在 Solid 中解决了 React useEffect hook 的问题,而无需编写看起来像 hooks 的东西。我们可以扩展我们的计数器例子来探索 Solid 效果。

如果我们想在每次计数增加时 console.log count 怎么办?你的第一反应可能是在我们的函数中使用 console.log:


function Counter() {const [count, setCount] = createSignal(0);setInterval(() => {setCount(count() + 1);}, 1000);console.log(`The count is ${count()}`);return

The count is: {count()}div>;

但这不起作用。请记住,Counter 函数只运行一次!但我们可以使用 Solid 的 createEffect 函数来获得想要的效果:


function Counter() {const [count, setCount] = createSignal(0);setInterval(() => {setCount(count() + 1);}, 1000);createEffect(() => {console.log(`The count is ${count()}`);return

The count is: {count()}div>;

这行得通!而且我们甚至不必告诉 Solid,说这个效果取决于 count 变量。这才是真正的响应式设计。如果在 createEffect 函数内部调用了第二个访问器,它也会让效果运行起来。

一些更有趣的 Solid 概念

响应性,而不是生命周期 hooks

如果你已经在 React 领域有一段时间的经验了,那么下面的代码更改可能真的会让你大跌眼镜:


const [count, setCount] = createSignal(0);setInterval(() => {setCount(count() + 1);}, 1000);createEffect(() => {console.log(`The count is ${count()}`);function Counter() {return

The count is: {count()}div>;

并且代码仍然是有效的。我们的 count 信号不需要存在于一个组件函数中,依赖它的效果也不需要。一切都只是响应式系统的一部分,“生命周期 hooks”实际上并没有起到太大的作用。

细粒度的 DOM 更新

前面我主要关注的是 Solid 的开发体验(例如更容易编写没有错误的代码),但 Solid 的性能表现也得到了很多赞誉。其强大性能的一个关键来源是它直接与 DOM 交互(无虚拟 DOM)并执行“细粒度”的 DOM 更新。

考虑对我们的计数器进行以下调整:


function Counter() {const [count, setCount] = createSignal(0);setInterval(() => {setCount(count() + 1);}, 1000);return (

The {(console.log('DOM update A'), false)} count is:{' '}{(console.log('DOM update B'), count())}

运行它会在控制台中获得以下日志:


DOM update ADOM update BDOM update BDOM update BDOM update BDOM update BDOM update B

换句话说,每秒更新的唯一内容是包含 count 的一小部分 DOM。Solid 甚至没有重新运行同一 div 中较早的 console.log。

小 结

在过去的几年里我很喜欢使用 React;在处理实际的 DOM 时,我总感觉它有着正确的抽象级别。话虽如此,我也开始注意到 React hooks 代码经常变得容易出错。我感觉 Solid.js 使用了 React 的许多符合人体工程学的部分,同时最大程度减少了混乱和错误。本文向你展示的是 Solid 的一些让我惊叹的部分,感兴趣的话我建议你查看 https://www.solidjs.com 并自己探索这个框架。

https://typeofnan.dev/solid-js-feels-like-what-i-always-wanted-react-to-be/

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
邓文迪的二女儿:身高超过1.8米还很聪明,23岁就硕士毕业了

邓文迪的二女儿:身高超过1.8米还很聪明,23岁就硕士毕业了

小书生吃瓜
2026-06-22 20:51:36
日本刚拿到12年稀土大单就飘了,叫嚣反制无效,不料麻烦才开始!

日本刚拿到12年稀土大单就飘了,叫嚣反制无效,不料麻烦才开始!

疯狂小菠萝
2026-06-23 17:16:11
辽宁省2026年高考成绩将于6月24日发布

辽宁省2026年高考成绩将于6月24日发布

半岛晨报
2026-06-23 14:35:01
发现一个现象:中产返贫三件套,已经升级为六件套了!

发现一个现象:中产返贫三件套,已经升级为六件套了!

番外行
2026-05-18 10:25:35
1.2万亿顺差创百年纪录,张燕生却警告:再赚下去,中国要有麻烦

1.2万亿顺差创百年纪录,张燕生却警告:再赚下去,中国要有麻烦

趣文说娱
2026-05-29 20:13:52
史无前例!特朗普在接受采访时透露,中美两国可能实现1年4次会面

史无前例!特朗普在接受采访时透露,中美两国可能实现1年4次会面

墨兰史书
2026-06-23 12:15:09
7分8板对不起NBA首轮身份!杨瀚森想打出统治力,需要一人回归

7分8板对不起NBA首轮身份!杨瀚森想打出统治力,需要一人回归

弄月公子
2026-06-23 21:52:02
强制征缴9千万,滞纳金几近税款双倍,滞后国税总局政策10多年;元芳,你怎么看?

强制征缴9千万,滞纳金几近税款双倍,滞后国税总局政策10多年;元芳,你怎么看?

立生自由谈
2026-06-23 07:39:05
台东海域有变数,两岸船只对峙,日方也介入了,大陆5部门已联手

台东海域有变数,两岸船只对峙,日方也介入了,大陆5部门已联手

起喜电影
2026-06-23 16:59:19
担忧!哈里怀抱儿女新照曝光,孩子们习性养成,即将拜见国王爷爷

担忧!哈里怀抱儿女新照曝光,孩子们习性养成,即将拜见国王爷爷

暖心萌阿菇凉
2026-06-23 17:12:18
湖北省纪委监委通报:1人被查

湖北省纪委监委通报:1人被查

荆头条
2026-06-24 01:23:59
进入梅雨季,建议:少吃猪肉,多吃4样,营养又养人,浑身都轻松

进入梅雨季,建议:少吃猪肉,多吃4样,营养又养人,浑身都轻松

刘哥谈体育
2026-06-24 03:34:44
天津最长公交线路揭秘:全程 67 公里,每一站都是海河风情

天津最长公交线路揭秘:全程 67 公里,每一站都是海河风情

娱乐圈的笔娱君
2026-06-24 00:00:27
真相来了!高市早苗怪不得喜欢挤眉弄眼,原来如此

真相来了!高市早苗怪不得喜欢挤眉弄眼,原来如此

白日追梦人
2026-06-23 13:35:04
该叫停了!签证审核形同虚设,印度人在中国已泛滥成灾

该叫停了!签证审核形同虚设,印度人在中国已泛滥成灾

超级学爸蛋总
2026-06-24 02:13:50
废掉一个人最快的方法:让他学满一肚子“无用的文化”

废掉一个人最快的方法:让他学满一肚子“无用的文化”

青苹果sht
2026-04-16 05:33:08
在莫斯科待了十年,我感悟到:非生理需求,都不碰莫斯科女友

在莫斯科待了十年,我感悟到:非生理需求,都不碰莫斯科女友

牛锅巴小钒
2026-06-23 03:29:03
韩红“走个面”风波升级,大量月捐人终止协议后,又接连曝出黑料

韩红“走个面”风波升级,大量月捐人终止协议后,又接连曝出黑料

追踪之点
2026-06-23 15:58:51
哈兰德世界杯小组赛梅开二度,女友晒雨中拥吻照,网友:太甜了

哈兰德世界杯小组赛梅开二度,女友晒雨中拥吻照,网友:太甜了

生性洒脱
2026-06-23 18:02:25
很多人可能根本活不到退休了。

很多人可能根本活不到退休了。

老陆不老
2026-06-21 16:13:37
2026-06-24 06:11:00
InfoQ incentive-icons
InfoQ
有内容的技术社区媒体
12562文章数 51955关注度
往期回顾 全部

科技要闻

48名中国开发者联名举报苹果

头条要闻

葡萄牙5-0乌兹别克斯坦 C罗梅开二度

头条要闻

葡萄牙5-0乌兹别克斯坦 C罗梅开二度

体育要闻

扬尼斯去了迈阿密:凯尔特人怎么办?

娱乐要闻

内娱95后顶流格局发生潜移默化的变化

财经要闻

AI“算力稀缺”信仰开始动摇?

汽车要闻

施鹏泽:为什么奥迪E7X强调座舱气味安全?

态度原创

艺术
旅游
数码
家居
教育

艺术要闻

高约400米!深圳湾金融中心大厦,冲出正负零

旅游要闻

端午假期忻州市累计接待游客98.29万人次,同比增长10.31%

数码要闻

AOC发布AGON PRO AGP277QKDC双模游戏显示器

家居要闻

绿意盎然 自然之境

教育要闻

6月23日(发布),2026上海高考分数线新鲜出炉,本科录取控制分数线403分

无障碍浏览 进入关怀版