作为用于创建高性能 Web 应用程序的最受欢迎的前端库之一,React 遵循基于组件的方法,其中每个组件都有自己的状态和逻辑。
如何在React中优化缓存?React 面临的最大挑战是避免不必要的渲染,这会导致严重的性能问题,尤其是在大型应用程序中。在本文中,我们将介绍几种不同的方法,通过不同的缓存方法来优化 React 应用程序的性能。
React优化缓存的方法:用于记忆的 React Hooks
记忆(Memoization)是 React 本身提供的一个特性。正如我们所知,React 每次重新渲染时都会创建新的引用。如果你的组件有大量计算,即使输出没有改变,也会在每次重新渲染时进行计算。
为了通过避免不必要的负载来使 CPU 负载最小化,React 提供了两个有助于记忆的 Hook。Hooks 遵循一个过程,其中结果被缓存在内存中,当我们得到相同的输入时,无需重新计算就返回。在不同输入的情况下,缓存失效。
useMemo()
React优化缓存实例教程:useMemo()
是 React 提供的用于记忆的 Hook,有助于保持缓存值与提供给它的值相同。它跟踪输入并返回先前执行的结果。
让我们看一个例子。假设我们必须在具有以下功能的组件中添加两个巨大的数字:
const addTwoHugeNumbers=(a,b)=>{
return a+b
}
上面写的函数对 CPU 来说很重,因此应该只在a
和的值b
改变时计算。但是,默认情况下,它将在每次重新渲染时运行。
使用useMemo()
,我们可以存储特定值的结果,这意味着函数不会计算,我们将直接获得先前计算的结果:
const memoizedValue = useMemo(() => addTwoHugeNumbers(a, b), [a, b])
该值存储在memoizedValue
. 我们已经将依赖数组传递给useMemo
,它告诉它什么时候再次运行。在我们的例子中,它会在任何一个值改变时运行。
UseCallback()
使用useCallback(),我们也获得了记忆的能力,但它以不同的方式工作。useCallback()不记忆值,而是记忆提供给它的回调函数。让我们看一个小例子:
const increment = (() => {
setCount(count + 1);
});
使用useCallback()
,上面的函数类似于下面的代码:
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
useCallback()
将记住增量函数,仅在给定的依赖项发生变化时运行。它不跟踪输入或函数返回的值。
延迟加载 React 组件
如何在React中优化缓存?React 中的延迟加载会预先呈现必要的组件,并将加载不重要的组件延迟到之后。
特别是在较大的应用程序中,强烈建议使用这种方法来提高性能。在 React 中,我们有内置选项来延迟加载组件。
我们已经创建了一个名为的组件</Artists>
,我们希望它延迟加载,我们可以这样做:
import { lazy } from 'react';
首先,我们从 react 中导入 lazy 并使用它,如下所示:
const Artists = React.lazy(() => import('./Artists'));
function App() {
return (
<div>
<Artists />
</div>
);
}
useRef()
React优化缓存的方法:我们知道,无论何时在组件中使用useState()
,当状态改变时,它都会在组件中重新呈现。为了跟踪状态而不引起重新呈现,React引入了useRef()
钩子。
在某些情况下,useState()
可能不是您的应用程序的正确解决方案。useRef()
非常适合于这样的情况:我们需要的状态不会导致重新呈现,并且对组件呈现的可见信息没有贡献。例如,你可以用它来计数渲染:
function App() {
const [foo, setFoo] = React.useState(false)
const counter = React.useRef(0)
console.log(counter.current++)
return (
<button onClick={() => setFoo(f => !f)} > Click </button>
)
}
ReactDOM.render(<React.StrictMode><App /></React.StrictMode>, document.getElementById('mydiv'))
在上面的代码中,我们有一个简单的切换器,用于重新呈现组件。Counter是一个持久化其值的可变ref。我们可以对useState()做同样的事情,但它会为每个切换导致两次呈现。
React优化缓存实例教程:Redux 缓存选择器
选择器只是用于从更大的数据池中选择数据的函数。在 React 中,选择器被广泛用于从 Redux 存储中获取值。选择器非常有用和强大,但它们也有自己的缺点。
在React Redux中,我们有useSelector()
钩子,用于从商店获取状态。useSelector()
的问题在于它在组件每次呈现时都会运行。useSelector()
在某些情况下可能是理想的,但大多数情况下,选择器返回的数据不会改变,这使得不必要的计算。
让我们看一个例子:
import React, {useEffect,useState} from 'react'
import {useSelector, useDispatch} from 'react-redux'
import {getPosts} from './postActions'
export const List=()=>{
Const [toggle, setToggle]=useState(false)
const myPosts=useSelector(state=>state.posts)
const dispatch=useDispatch()
return(
<div>
{myPosts.map(post=><p>{posts}<p/>)}
<button type="button" onClick={()=>{setToggle(!toggle)}} >Click Me!</button>
<div/>
)
}
在上面的代码中,我们正在更改切换状态,并且每次我们执行此操作时组件都会呈现。该挂钩也将运行,即使职位不符合我们的终极版店内改变。useSelector()
为了解决这个问题,我们将缓存一个选择器函数的结果。尽管没有内置的 React 解决方案,但我们有许多第三方库允许我们创建缓存选择器。让我们使用 Reselect,这是缓存选择器的著名解决方案。
Reselect
React优化缓存的方法:Reselect 是一个流行的库,用于创建记忆化选择器。你可以使用以下命令将其安装到你的项目中:
yarn add reselect
我们可以使用 Reselect 如下:
import { createSelector } from 'reselect'
import React, {useEffect,useState} from 'react'
import {useSelector, useDispatch} from 'react-redux'
import {getPosts} from './postActions'
export const List=()=>{
Const [toggle, setToggle]=useState(false)
const myPosts = createSelector(state=>state.posts)
const dispatch=useDispatch()
return(
<div>
{myPosts.map(post=><p>{posts}<p/>)}
<button type="button" onClick={()=>{setToggle(!toggle)}} >Click Me!</button>
<div/>
)
}
在上面的代码中,我们createSelector
从 Reselect导入,它接受一个选择器并返回它的记忆版本。使用记忆化版本,即使经过数千次重新渲染,组件也不会计算选择器的值,除非值发生postReducer
变化。createSelector
事实证明,Reselect 是解决大型应用程序性能问题的绝佳解决方案。
使用 React Query 优化 API 调用
如何在React中优化缓存?React 以自己的方式处理异步操作,这有时是开发人员的一个问题。异步操作的常用模式是在useEffect
Hook 中获取服务器数据,它在每次渲染时运行并每次获取新数据,即使服务器上没有新数据。
另一方面,React Query 缓存数据并在调用之前先返回它,但是如果服务器返回的新数据与之前的数据相同,React Query 将不会重新渲染组件。我们可以使用 React Query 如下:
import React from 'react'
import {useQuery} from 'react-query'
import axios from 'axios'
async function fetchPosts(){
const {data} = await axios.get('https://jsonplaceholder.typicode.com/posts')
return data
}
function Posts(){
const {data, error, isError, isLoading } = useQuery('posts', fetchPosts)
// first argument is a string to cache and track the query result
if(isLoading){
return <div>Loading...</div>
}
if(isError){
return <div>Error! {error.message}</div>
}
return(
<div className='container'>
<h1>Posts</h1>
{
data.map((post, index) => {
return <li key={index}>{post.title}</li>
})
}
</div>
)
}
export default Posts
React片段
React优化缓存实例教程:如果你是 React 开发人员,你可能遇到过一个错误,提示将组件与父 div 包装在一起。如果你的组件中不需要额外的 div,则添加它没有意义。例如,如果你的 React 应用程序中有 1000 个组件,那么你将有 1000 个额外的 div,这对 DOM 来说可能很重。为了避免这种情况,React 为你提供了使用片段的选项:
const Message = () => {
return (
<React.Fragment>
<p>Hello<p/>
<p>I have message for you<p/>
</React.Fragment>
);
};
下面的代码片段与上面的代码完全相同,<>
用作React.Fragment
的快捷方式:
const Message = () => {
return (
<>
<p>Hello<p/>
<p>I have message for you<p/>
</>
);
};
无论使用哪种方法,都可以避免添加额外的<div>
,从而减少 DOM 标记、提高渲染性能并减少内存开销。
React虚拟列表
如何在React中优化缓存?通常,我们需要在浏览器上呈现大型列表;这样做对浏览器来说是很复杂的,因为它必须创建新节点并将它们全部绘制在屏幕上。
为了使 React 中的过程高效,我们可以选择使用虚拟列表。虚拟列表仅根据需要呈现少数项目,只需在用户动态滚动项目时替换它们。
渲染比更改 DOM 更快,因此你可以使用虚拟列表以快速的性能渲染数千个列表项。React-virtualized是一个优秀的库,它具有渲染虚拟列表的组件。
React优化缓存的方法:功能组件
React 从基于类的组件开始,但是,由于其轻量级的特性,现在建议使用函数式组件。功能组件基本上是创建速度更快的函数,并且它们更容易缩小,从而减小包的大小。
React优化缓存实例教程结论
在本教程中,我们介绍了几种用于优化 React 应用程序中缓存管理的不同解决方案,例如记忆、缓存选择器、延迟加载、React 片段、虚拟列表和功能组件。这些方法中的每一种都可以通过减少不必要的组件渲染数量、减少开销和提高速度来改进你的应用程序。
正确的解决方案将取决于你个人项目的需求,但希望本文能帮助你了解可用的选项。