8倍的React Performance:让您的应用程序飞速发展
优化是每个开发人员最重要的方面之一,尤其是在构建Web应用程序时。通过使用虚拟DOM,React使UI更新尽可能高效。
React如何工作
每个React应用程序都由许多树形组件组成。组件是根据收到的道具渲染UI的功能。每当数据发生变化时,React计算机就会将当前用户界面和新用户界面之间的差异进行更改,然后继续将用户界面更改应用于浏览器上的实际用户界面。重复的比较和渲染组件可能是React性能问题的主要原因之一。
我们希望React只重新渲染受其接收的数据(状态或道具)更改影响的组件。在本文中,我将向您展示8种不同的技术来提高应用程序的整体性能。让我们开始工作吧
- 避免将索引用作键
- UseEffect()和UseCallback()
- 反应备忘录
- 反应片段
- 延迟加载
- 渐进图像
- JS动画代替CSS动画
- 生产建立
0.设置
让我们开始创建一个基本的React功能组件,该组件使用axios从API提取数据并将列表显示到UI。我们的状态跟踪加载,错误和传入的dataU。通过将useEffect与useCallback结合使用,可以确保不会在每个渲染器上再次调用API获取。
对于API,我将选择一个随机有趣的公共API,即Cocktail Database API。在这里,您可以找到免费的公共API列表。
创建一个新的React应用 npx create-react-app perf-test
并加载上面的代码。
衡量绩效
我们将使用Chrome性能标签来衡量React应用的性能,这就是React的建议。确保禁用所有Chrome扩展程序,尤其是React DevTools。因为它们会大大扭曲结果。我还将CPU的速度降低6倍,以重现大量数据并降低计算机速度。
1.避免使用索引作为键
我在上面创建的示例获取25种鸡尾酒配方的列表,并使用户可以将自己的配方添加到列表中。
当用户添加新鸡尾酒时,addCocktail()函数将更新我们的鸡尾酒状态钩。使用useRef()可以引用输入字段,并确保它们不为空。
此示例中的问题是,每次添加新配方时,组件都会完全重新渲染。当您在Chrome Devtools中启用绘画刷新时,您可以看到更新了哪些DOM节点。
渲染时间:336ms
这是因为数组中的每个鸡尾酒都向右推了一个索引。很大的改进是使用唯一ID而不是索引。您可以使用npm软件包uuid生成唯一的ID。
...
const updatedCocktails = [
{
idDrink: uuidv4(),
strDrink: currentName,
strInstructions: currentDescription
}
].concat(cocktails);
...
cocktails.map((cocktail, index) => {
const { idDrink, strDrink, strInstructions } = cocktail;
return (
<div key={idDrink}>
<strong>{strDrink}</strong> - {strInstructions}
</div>
);
})
...
渲染时间:233ms
太棒了让我们继续。
2. useEffect()和useCallback()
一旦组件安装好,我们就使用useEffect()挂钩来获取鸡尾酒。仅当依赖关系更改时,它才会重新运行(在这种情况下为getCocktails函数。通过useCallback(),我们确保每次App组件重新渲染时都不会获取API数据。
在我们的示例中,这不会带来太大的改变,但是当您有一个拥有很多子组件的巨大组件时,在这种情况下,getCocktails更改状态或道具时,不完全重新渲染该组件可能会产生很大的影响。父组件的
function App() {
const getCocktails = useCallback((query) => {
axios
.get(`https://www.thecocktaildb.com/api/json/v1/1/search.php?f=${query}`)
.then((response) => {
setCocktails(response.data.drinks);
setIsLoading(false);
})
.catch((error) => {
setErrors(error);
});
}, []);
useEffect(() => {
getCocktails("a");
}, [getCocktails]);
}
在上面的代码中,该效果将在任何时候重新运行 getCocktails
进行更改以确保它具有最新版本的 getCocktails
。的 getCocktails
每次都会重新创建功能 App
无需使用即可重建 useCallback
函数,并在更改状态或道具时调用无限循环 App
。
useCallback
通过将其盘点在函数声明周围并定义函数的依赖项来帮助防止此情况,它确保仅在函数的依赖项发生更改时才重新创建该函数。因此,不再在每个渲染周期都重新构建该功能。
3.记住React组件
React.Memo是一个高阶组件(HOC),它通过记忆结果来盘点另一个组件,这意味着React将跳过渲染该组件,并重用上一个渲染的结果。这可以提高您的应用程序的性能。
我们可以将鸡尾酒div存储在其自己的无状态功能组件中,并用React.Memo()盘点。
// index.js
...
cocktails.map(({ idDrink, ...otherProps }) => (<Cocktail key={idDrink} {...otherProps} />))
...
// Cocktail.js
import React from "react";
const Cocktail = ({ strDrink, strInstructions }) => {
return (
<div>
<strong>{strDrink}</strong> - {strInstructions}
</div>
);
};
export default React.memo(Cocktail);
渲染时间:192ms
4. React.Fragments
在React的一个组件中通常有多个组件。您始终需要将孩子盘点成1个主要组成部分。使用Fragments,您可以避免为主盘点器组件添加更多DOM节点。您可以使用
标记并从React导入,或使用空标记 <>>
例:
return (
<>
<h2>Cocktails</h2>
{!isLoading ? (
cocktails.map(({ idDrink, ...otherProps }) => (
<Cocktail key={idDrink} {...otherProps} />
))
) : (
<p>Loading...</p>
)}
</>
);
在我们的示例中,差异很小,但是如果您有成千上万个使用div的组件,则可以在性能上产生很大差异。
5.延迟加载
React的另一个本机方法是React.lazy函数,它将在当前组件渲染后立即加载请求的组件。
例如:
// Normal
import Home from '../screens/Home';
// Lazy
const Home = lazy(() => import("../screens/Home"));
惰性组件必须在
组件,以便用户在加载组件时看到后备项。
<Suspense fallback={<Fragment>Loading...</Fragment>}>
<Switch>
<Route exact path="/" component={Home} />
</Switch>
</Suspense>
6.渐进式图像加载
加载时在Medium.com上看到的图像模糊吗?他们正在使用渐进式图像加载,这基本上意味着您在加载高分辨率图像时会显示较低质量的版本图像。
react-progressive-image包是将其集成到您的应用程序的好方法。
...
import ProgressiveImage from "react-progressive-graceful-image";
import ProfileImgLarge from "../assets/img/profile-large.jpg";
import ProfileImgPlaceholder from "../assets/img/profile-placeholder.jpg";
...
<ProgressiveImage
src={ProfileImgLarge}
placeholder={ProfileImgPlaceholder}
>
{(src) => (
<ProfileImage src={src} alt="Profile of Sander de Bruijn" />
)}
</ProgressiveImage>
...
使用这种技术,您可以通过使用例如<10kb图片作为占位符。
7. JS动画而不是CSS动画。
实际上,许多开发人员认为CSS动画比JS动画具有更好的性能,但是本文显示了使用复杂动画时的相反情况。除此之外,基于JavaScript的动画还提供了更大的灵活性,更好的工作流以处理复杂的动画和丰富的交互性。
对于简单的动画,CSS可以正常工作。但是对于更复杂的应用程序,我建议使用GSAP库。
8.生产建设
这具有最大的影响。在开发中,React提供了大量的附加组件,使我们的生活更轻松。但是,用户不需要这些附加组件。通过执行 yarn build
(或npm build)webpack在使用create-react-app时为我们构建输出文件夹。
渲染时间:<60ms
这就对了希望您从本教程中学到了一些东西。请务必关注我,以获取更多提示和技巧。