我正在探索优化 Web 应用程序性能的选项,特别是在最大限度地减少不必要的重新渲染/重新计算方面。我遇到过 Preact Signals,它似乎提供了 React hooks 的一个有趣的替代方案。根据我的理解,Preact Signals 允许在信号值发生变化时进行粒度更新,而无需重新渲染整个 DOM 树,从而带来潜在的性能提升。
相比之下,React 的状态挂钩可能会导致额外的重新渲染,但可以使用各种优化技术来缓解这些问题,例如
useMemo
、useCallback
、React.memo
、....
鉴于这种背景,我正在尝试评估哪种方法会在现实场景中产生更好的性能:
useMemo
、useCallback
、React.memo
...结合使用,以防止不必要的重新渲染/重新计算。我遇到过许多基准测试,将未优化的 React 应用程序与在 React 中使用 Signals 的应用程序进行比较,但我对上述两种情况的比较感兴趣。
我有兴趣了解权衡和潜在的性能影响。
Preact 是 React 的轻量级替代品,具有更小的包大小。 Preact Signals 提供了反应式编程模型,允许有效更新以响应状态变化。 Preact 较小的尺寸可以缩短应用程序的初始加载时间,特别是在捆绑包大小至关重要的情况下。
但不仅如此。您可以通过避免 vDOM 来实现真正的性能提升,这是一件美妙的事情。取决于你如何实现它们,但直接读取 signal.value 而不使用 useSignals() 或转换器会带来惊人的结果。
他们已经在博客上解释了很多这些改进: https://preactjs.com/blog/introducing-signals/
在现实世界中,信号成为我状态管理的首选方法。它们也很容易调试。
嗨,有点晚了,但我在这里: 我一直在我的上一个项目中使用信号,这绝对是我从现在开始的方式,我不仅实现了信号,我在组件之外拥有所有的反应应用程序状态,并且该应用程序是细粒度和快速的,没有样板,告别 React hook 问题,这是我的方法:
由于信号不允许React代码对对象的变化做出反应,所以我使用deepSignal,它就像信号升级了:
import { deepSignal } from "deepsignal/react";
export class SignalState {
constructor(props, func) {
this.props = props
this.func = func
this.signal = deepSignal({});
this.init()
}
init() {
for (const key in this.props) {
if (Object.prototype.hasOwnProperty.call(this.props, key)) {
this.signal[key] = this.props[key]
}
}
for (const key in this.func) {
if (Object.prototype.hasOwnProperty.call(this.func, key)) {
this.signal[key] = this.func[key].bind(this.signal);
}
}
return this.signal;
}
}
这堂课是为了什么? 由于每个状态都需要值和方法,在这里你可以在任何你想要的地方定义你的状态(在任何地方工作),我更喜欢在组件之外使用它。 例子: 成分:
import {testSignal} from "./testSignal.js";
const {signal} = testSignal
//debugger
export default function Test() {
//debugger
return (
<div style={{display: 'flex', flexDirection: 'column'}}>
<span>{`dynamic: ${signal.dynamic?.toString()}`}</span>
<span>{`test: ${signal.newValue?.toString()}`}</span>
<span>{`test: ${signal.test?.toString()}`}</span>
<button onClick={signal.toggleTest}>Toggle Test</button>
{/*<button onClick={toggleDynamic}>Toggle Dynamic</button>*/}
<button onClick={signal.increment}>Increment</button>
</div>
);
}
测试信号:
import {SignalState} from "../../../../signals/SignalClass.js";
import {effect} from "@preact/signals-react";
export const testSignal = new SignalState({
dynamic: false,
newValue: 1,
test: false,
}, {
increment() {
this.newValue = this.newValue + 1
},
toggleTest() {
this.test = !this.test
}
})
// effect(() => {
// console.log([testSignal.signal?.newValue, testSignal.signal?.test])
// })
正如您所看到的,甚至效果、计算和所有信号带来的工作都完美地在这里工作,并且您相应地对组件更新做出反应,这样您的组件每次只渲染一次,并且每个信号都是全局的,因为您正在导出实例。
在你问这是否表现良好之前,我已经使用这个实现运行了这个https://dmvapp.pro,你可以去尝试一下,看看你自己的加载时间和响应时间。