引言
性能优化是软件开发中永远不会过时的话题,本篇将介绍在React编码过程中3个性能优化点:memo
、useCallback
、useMemo
。
memo
memo
是 React 提供的一个高阶组件(HOC),用于缓存函数组件。它的作用是防止组件在父组件重新渲染时,不必要的重新渲染。memo
会对组件的 props 进行浅比较,如果 props 没有变化,组件就不会重新渲染。
- 组件渲染成本较高:当组件的渲染成本较高时(例如,组件内部有复杂的计算或大量的子组件),使用
memo
可以显著提高性能。 - props 不经常变化:当组件的 props 不经常变化时,使用
memo
可以避免不必要的渲染。 - 浅比较:
memo
默认使用浅比较来比较 props。如果 props 是对象或数组,浅比较可能无法检测到深层的变化。在这种情况下,可以自定义比较函数。
import { memo } from "react";
interface BobProps {
count: number;
callback: () => void;
}
function Bob(props: BobProps) {
console.log('Bob------');
return <h2>{props.count}</h2>;
}
const MemoBob = memo(Bob);
在这个例子中,Bob
组件被 memo
包裹,生成了一个新的组件 MemoBob
。当父组件重新渲染时,如果 MemoBob
的 props 没有变化,Bob
组件就不会重新渲染。
useCallback
useCallback
是 React 提供的一个钩子,用于缓存函数。它的作用是避免在每次渲染时都重新创建函数,从而减少不必要的渲染。
- 函数作为 props 传递:当函数作为 props 传递给子组件时,使用
useCallback
可以避免子组件不必要的渲染。 - 依赖项变化时重新创建函数:当函数的依赖项变化时,使用
useCallback
可以确保函数只在依赖项变化时重新创建。 - 依赖项:
useCallback
的第二个参数是依赖项数组。如果依赖项发生变化,函数会重新创建。
import { useCallback } from "react";
function Aaa() {
const [count, setCount] = useState(1);
const bbbCallback = useCallback(() => {
console.log('bbbCallback');
}, []);
return (
<div>
<MemoBob count={count} callback={bbbCallback} />
</div>
);
}
在这个例子中,bbbCallback
函数被 useCallback
缓存。由于 useCallback
的依赖项为空数组,bbbCallback
函数只会在组件挂载时创建一次,后续渲染时不会重新创建。
useMemo
useMemo
是 React 提供的一个钩子,用于缓存计算结果。它的作用是避免在每次渲染时都重新计算值,从而减少不必要的计算。
- 计算成本较高:当计算成本较高时(例如,复杂的数学运算或数据处理),使用
useMemo
可以显著提高性能。 - 依赖项变化时重新计算:当计算结果的依赖项变化时,使用
useMemo
可以确保计算结果只在依赖项变化时重新计算。
import { useMemo } from "react";
function Aaa() {
const [count1, setCount1] = useState(1);
const [count2, setCount2] = useState(2);
const product = useMemo(() => {
console.log('/////');
return count1 * count2;
}, [count1, count2]);
return (
<div>
<p>Count1: {count1}</p>
<button onClick={() => setCount1(count1 + 1)}>增加Count1</button>
<p>Count2: {count2}</p>
<button onClick={() => setCount2(count2 + 1)}>增加Count2</button>
<p>乘积: {product}</p>
</div>
);
}
在这个例子中,product
的值被 useMemo
缓存。只有当 count1
或 count2
发生变化时,product
才会重新计算。
4. 综合应用
在实际项目中,memo
、useCallback
和 useMemo
通常会结合使用,以达到最佳的性能优化效果。以下是一个综合应用的示例:
// memo 性能优化 缓存 减少不必要的渲染
// useCallback 缓存函数
// useMemo 缓存计算结果
import { useEffect,useState,memo,useCallback,useMemo } from "react";
// 面向对象的核心概念
// 接口 定义对象结构 确保实现该接口的类或对象 具有特定的属性和方法
// 满足接口 安全
interface BobProps {
count: number;
callback: () => void;
}
// 没有必要更新的组件能不能不更新?
// 函数参数要给类型约定
function Bob(props: BobProps) {
console.log('Bob------');
return <h2>{props.count}</h2>
}
// 缓存
// 参数是一个组件 将一个组件返回一个新组件的函数 叫做高阶组件
// 函数的参数或返回值是函数 叫做高阶函数
const MemoBob = memo(Bob);
// console.log(MemoBob);
const MemoExample = () => {
const [count1,setCount1] = useState(1);
const [count2,setCount2] = useState(2);
const [count3,setCount3] = useState(3);
const product = useMemo(() => {
console.log('/////');
return count1 * count2;
},[count1,count2])
return (
<div>
<p>Count1:{count1}</p>
<button onClick={() => setCount1(count1 + 1)}>增加Count1</button>
<p>Count2:{count2}</p>
<button onClick={() => setCount2(count2 + 1)}>增加Count2</button>
<p>Count3:{count3}</p>
<button onClick={() => setCount3(count3 + 1)}>增加Count3</button>
<p>乘积{product}</p>
</div>
)
}
function Aaa() {
// 响应式数据发生改变之后 整个函数会重新执行
const [count,setCount] = useState(1);
const [num, setNum] = useState(1); // useState 会特殊处理 不会每次都重新执行
console.log('-----');
// mounted
useEffect(() => {
setInterval(() => {
setNum(Math.random())
},2000)
setTimeout(() => {
setCount(3)
},1000)
},[]); // 挂载和卸载时执行 [] 也不会重新执行
// 函数会重新创建
// useCallback 缓存函数
// useMemo 缓存计算结果
// 第二个参数是依赖项
const bbbCallback = useCallback(() => {
console.log('bbbCallback');
// count num
},[])
const count2 = useMemo(() => {
return count*10;
}, [count])
// 重新执行
return (
<div>
{num}
{/* <Bob count = {2}></Bob> */}
<MemoBob count={count2} callback={bbbCallback}/>
<MemoExample />
</div>
)
}
export default Aaa;
5. 总结
React 提供了多种工具来帮助我们优化性能,其中 memo
、useCallback
和 useMemo
是最常用的几种。通过合理地使用这些工具,我们可以显著提高应用的性能,尤其是在处理大型应用或复杂组件时。然而,需要注意的是,这些工具本身也有一定的性能开销,因此只有在确实需要时才使用它们。
在实际项目中,我们应该根据具体的场景和需求,灵活地使用这些工具,以达到最佳的性能优化效果。同时,我们还应该注意代码的可读性和可维护性,避免过度优化导致代码难以理解和维护。
希望本文能够帮助你更好地理解 memo
、useCallback
和 useMemo
,并在实际项目中应用它们,提升你的 React 应用性能。