比较性能:带有优化的 React Hooks 与 Preact Signals

问题描述 投票:0回答:2

我正在探索优化 Web 应用程序性能的选项,特别是在最大限度地减少不必要的重新渲染/重新计算方面。我遇到过 Preact Signals,它似乎提供了 React hooks 的一个有趣的替代方案。根据我的理解,Preact Signals 允许在信号值发生变化时进行粒度更新,而无需重新渲染整个 DOM 树,从而带来潜在的性能提升。

相比之下,React 的状态挂钩可能会导致额外的重新渲染,但可以使用各种优化技术来缓解这些问题,例如

useMemo
useCallback
React.memo
、....

鉴于这种背景,我正在尝试评估哪种方法会在现实场景中产生更好的性能:

  1. 一个 React.js 应用程序,其中状态钩子与
    useMemo
    useCallback
    React.memo
    ...结合使用,以防止不必要的重新渲染/重新计算。
  2. 使用 Reactjs 和 Signals 进行状态管理的应用程序。

我遇到过许多基准测试,将未优化的 React 应用程序与在 React 中使用 Signals 的应用程序进行比较,但我对上述两种情况的比较感兴趣。

我有兴趣了解权衡和潜在的性能影响。

reactjs preact
2个回答
1
投票

Preact 是 React 的轻量级替代品,具有更小的包大小。 Preact Signals 提供了反应式编程模型,允许有效更新以响应状态变化。 Preact 较小的尺寸可以缩短应用程序的初始加载时间,特别是在捆绑包大小至关重要的情况下。

但不仅如此。您可以通过避免 vDOM 来实现真正的性能提升,这是一件美妙的事情。取决于你如何实现它们,但直接读取 signal.value 而不使用 useSignals() 或转换器会带来惊人的结果。

他们已经在博客上解释了很多这些改进: https://preactjs.com/blog/introducing-signals/

在现实世界中,信号成为我状态管理的首选方法。它们也很容易调试。


0
投票

嗨,有点晚了,但我在这里: 我一直在我的上一个项目中使用信号,这绝对是我从现在开始的方式,我不仅实现了信号,我在组件之外拥有所有的反应应用程序状态,并且该应用程序是细粒度和快速的,没有样板,告别 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,你可以去尝试一下,看看你自己的加载时间和响应时间。

© www.soinside.com 2019 - 2024. All rights reserved.