我在开发的反应应用程序时遇到了一些性能问题。这些问题特别(或最明显地(发生在Firefox(FF开发者77.0b7和FF 76.0.1(上。
在 Firefox 中使用此应用程序时,CPU 使用率变得非常高,我的风扇开始以非常高的速度旋转。根据FF中的性能工具,我在Firefox中获得了大约15-19fps。我在Chrome和Safari中获得了大约60fps。
当我开始在输入字段中键入时,会出现这些问题,并且随着输入变长而变得更糟(这是有道理的(
该应用程序可在此处获得: https://text-to-aura-generator.netlify.app/
此处提供的源代码:https://github.com/paalwilliams/Text-to-Aura/tree/master/src
我几乎可以肯定这是我做错了,或者我编写的代码效率低下,但这不一定得到浏览器之间明显性能差异的支持。铬有那么好吗,处理反应/常量重新渲染?
我知道这是一个广泛的问题,但老实说,我不明白这里发生了什么,或者不一定知道如何在开发人员工具之外对其进行故障排除。任何意见或想法将不胜感激。
问题是您的应用程序渲染速度太快。在您的特定情况下,有几种方法可以改善这一点。
每次更新状态时,React 都需要重新渲染你的应用程序,因此在循环中更新状态通常是一个坏主意。
此外,您正在使用 3 次useState
,但只有colors
应该在那里,因为App
实际上需要重新渲染以反映那里的更改。另外两个状态(text
和hex
(仅用于将数据从handleChange
传递到useEffect
内部的回调。
您可以重构代码以:
-
避免在循环中更新状态。
-
使用简单变量而不是状态。
-
使用
useCallback
定义一个具有该逻辑的函数,该逻辑不会在每次渲染时重新创建,因为这也会强制TextInput
重新渲染。 -
使用如下所示的内容限制此回调:
import { useCallback, useEffect, useRef } from 'react'; export function useThrottledCallback<A extends any[]>( callback: (...args: A) => void, delay: number, deps?: readonly any[], ): (...args: A) => void { const timeoutRef = useRef<number>(); const callbackRef = useRef(callback); const lastCalledRef = useRef(0); // Remember the latest callback: // // Without this, if you change the callback, when setTimeout kicks in, it // will still call your old callback. // // If you add `callback` to useCallback's deps, it will also update, but it // might be called twice if the timeout had already been set. useEffect(() => { callbackRef.current = callback; }, [callback]); // Clear timeout if the components is unmounted or the delay changes: useEffect(() => window.clearTimeout(timeoutRef.current), [delay]); return useCallback((...args: A) => { // Clear previous timer: window.clearTimeout(timeoutRef.current); function invoke() { callbackRef.current(...args); lastCalledRef.current = Date.now(); } // Calculate elapsed time: const elapsed = Date.now() - lastCalledRef.current; if (elapsed >= delay) { // If already waited enough, call callback: invoke(); } else { // Otherwise, we need to wait a bit more: timeoutRef.current = window.setTimeout(invoke, delay - elapsed); } }, deps); }
如果使用useEffect
的原因是您在更新colors
时没有看到正确的值,请尝试使用接受回调而不是新值的setState
版本,而不是:
setColors([...colors, newColor]);
您将拥有:
setColors(prevColors => ([...prevColors , newColor]));
react 最常见的性能问题来自设置状态的次数过多,因为您不断重新渲染页面及其中的元素。