
我们都知道 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://github.com/nanxiaobei
|
9
yukinotech 2022-04-22 05:11:21 +08:00
@wonderblank 对的,起码自己可以控制什么时候该 redner
|