

我们都知道 SolidJS ,如果不知道,那你为啥要看这篇文章 ( ̄ ̄)"
我们都知道 SolidJS ,这是它的文档: https://www.solidjs.com/
简单来说,SolidJS 就是真正 "react" 版的 React ,完全按需更新(哪里不懂点哪里),哪里数据变化更新哪里。
比如一个组件:
function App() { const [value, setValue] = useState(0); return <div>{value}</div>; } React 是把 App 整个函数死去活来的调用(即 re-render ),而 SolidJS 则只更新 value 那一小块。
当然,SolidJS 中是这么写的:
function App() { const [value, setValue] = createSignal(0); return <div>{value()}</div>; } 在 SolidJS 中, App 只在初始化时被调用一次,之后就不再执行。
所以 SolidJS 里的 JSX 相当于 "静态模板",只用来描述 UI 而不会再次调用,更没有 diff 。
也就是说,随便在 App 里执行函数,随便在 JSX 里执行函数,都只触发一次。
如何把 React 变为 SolidJS ?
当然不是把 solid-js 重命名 react,也不是手动操作 DOM 脱离 React 的逻辑去更新。
这里必须声明一下:
以下实现,完全是基于 React 的 API 做的,而不是用 DOM API 或 jQuery 来 hack 实现的,那样的话就失去了意义。
value() 一小块?这里是实现思路的核心所在,直接说了吧 就是把 value() 变成一个组件。
是的,它展示的是数据,但它其实是一个组件。它是一个只返回数据的组件。
value() 而不是 value?因为需要知道这里有一个数据,后续得更新,怎么知道呢?
根据 JS 语法,除了 state.value(监听 getter)或 value()(调用函数),别无他法。
这也是为什么 SolidJS 必须写成 value(),如果写成 value,神仙也不知道怎么去更新这个数据,因为在 "静态模板" 的实现方式下,函数不会再次运行。
createSignal 的 useSignal我们希望实现一个 useSignal,类似 SolidJS 的 createSignal,返回 getter 和 setter 两个函数。
同时,getter 的返回得是一个组件。
function useSignal(val) { const valRef = useRef(val); const update = useRef(); const Render = () => { const [value, setValue] = useState(valRef.current); update.current = setValue; return value; }; const getter = () => { try { useState(); // 通过此 hack 获知数据是在 JSX 中,还是其它位置正常读取 return <Render />; } catch (e) { return valRef.current; } }; const setter = (newVal) => { valRef.current = newVal; update.current(newVal); }; return [getter, setter]; } 上面是一个极简实现,但有问题,因为数据可能用在多处,而上文只能更新最后一处的数据。
useSignal用一个 listeners 数组将更新函数们收集起来,这样就行了。其实这也是 React 状态管理器们的实现思路。
function useSignal(val) { const valRef = useRef(val); const listeners = useRef([]); const Render = () => { const [value, setValue] = useState(valRef.current); useEffect(() => { listeners.current.push(setValue); return () => { listeners.current.splice(listeners.current.indexOf(setValue), 1); }; }, []); return value; }; return [ () => { try { useState(); return <Render />; } catch (e) { return valRef.current; } }, (payload) => { listeners.current.forEach((listener) => { listener((prev) => { valRef.current = typeof payload === 'function' ? payload(prev) : payload; return valRef.current; }); }); }, ]; } 上面已经是一个可用的实现。
写到这里,其实故事的核心已经讲完了。
但如果要真用于开发需求,还有很多未尽的事业。
如果要真的 "可用",最起码还应该实现:
上面写了一堆问题,自然是准备好了答案 ... 这个答案就叫 solid-react。
上文提到的所有问题都解决了,若深入了解的话可以看源码。
GitHub: https://github.com/nanxiaobei/solid-react
下面是 solid-react 的 API:
Run(() => fn(value()))请注意 API 的命名,这也是有说法的:尽量不与已有 API 冲突(比如不直接命名为 useState useMemo,那样的话会让代码一团迷惑),同时还得保持足够的简洁(写起来不费事)和直观(理解起来不费事)。
具体 API 介绍请查看 README: https://github.com/nanxiaobei/solid-react 。
如此,已经可以覆盖大多数常见的开发场景,也就是可用于 "生产" 了。
Demo: https://codesandbox.io/s/solid-react-rymhr6?fOntsize=14&hidenavigation=1&theme=dark&file=/src/App.js
这里是一个 demo ,可以打开 console ,点击按钮试试,然后你就会发现:
组件再也不 re-render 了,React 完全变成了 SolidJS 式的按需更新!
useUpdate useAuto 也不需要 deps 之类的玩意,对其依赖都是自动获知。而且只有在依赖变化时,它们才再次执行。
是的,也就是可以摆脱 Hooks 了,什么 useCallback useMemo deps memo,会不会触发 re-render ,通通不需要了。
函数就是函数,对象就是对象,写在那里就不会再次新建了,完全不需要再包一层,随便给子组件 props 传递吧。
solid-react 是一个实验项目,只是为了实现一个想法,而事实上实现的还不错。
solid-react 尽力做成了 "能力完备",无论是发请求,还是监听数据,麻雀虽小(但很好吃),五脏俱全。
solid-react 是一个小东西,它可能会有缺陷,当然不能跟直接用 React 开发的成熟度对比,也不可能比。
solid-react 用于小 demo 项目肯定没问题,但未在大项目中实践过,它适合先用来玩一下,如果感兴趣的话。
solid-react 更像是一种理念,React 官方不可能走上这条路,但感谢开源,大可以自己在这条路上实验一下。
solid-react 为 "饱受 Hooks 写法困扰" 这一好几年也没消失的业界普遍困惑而努力(虽然我自己感觉 Hooks 还好)
solid-react 欢迎感兴趣的人一起尝试,创造出更多可能。
将 React 变成 SolidJS ,告别 Hooks ,告别 re-render ↓↓↓
https://github.com/nanxiaobei/solid-react
肯定有人想说,上面 solid-react 的 API 不就是 Hooks 吗?怎么告别 Hooks !其实上面是为了兼容 React 和 solid-react 混用的情况 ... 是的,我连这种情况都考虑到了
1 wonderblank 2022-04-08 07:31:14 +08:00 via iPhone 东西蛮好的,op 是怎么理解 “ React 是把 App 整个函数死去活来的调用(即 re-render )” ?我反而觉得这个是个好事情。 |
2 KuroNekoFan 2022-04-08 15:20:17 +08:00 要把一个 expression 变成一个 call....这么核心的改动怎么可以说“完全是基于 React 的 API 做的”.... |
3 alexsunxl 2022-04-08 17:51:39 +08:00 没啥意义啊, 你要自己怼一个生态出来吗? 复杂的场景搞不定。。。 玩具都不好玩的感觉。 |
4 nanxiaobei OP |
5 IvanLi127 2022-04-08 23:42:38 +08:00 via Android 我喜欢 hooks ,我好像也挺喜欢一直掉组件函数我是变成 react 的形状了吗 |
6 linkopeneyes 2022-04-09 13:07:16 +08:00 有没有像我一样就喜欢写 class 组件的 |
7 alexsunxl 2022-04-09 14:42:50 +08:00 @nanxiaobei 好吧。加油。能做出一些东西,还是挺棒的。 |
8 nanxiaobei OP @alexsunxl #7 嗯不需要加油,我做了很多东西了,欢迎查看 https://githubcom/nanxiaobei |
9 yukinotech 2022-04-22 05:11:21 +08:00 @wonderblank 对的,起码自己可以控制什么时候该 redner |