下面通过具体实例来展示 React 中的重新渲染(re-render)问题以及如何使用 useMemo 进行优化。
当组件的状态或 props 变化时,React 会重新执行组件函数(重新渲染)。如果组件中有复杂计算或子组件传递了新的引用类型值,可能导致不必要的重新渲染。
import { useState } from 'react';
// 子组件:显示用户信息
const UserInfo = ({ user, onUpdate }) => {
console.log('UserInfo 重新渲染了'); // 用于跟踪渲染
return (
<div>
<p>姓名:{user.name}</p>
<p>年龄:{user.age}</p>
<button onClick={onUpdate}>增长年龄</button>
</div>
);
};
// 父组件:包含状态和计算逻辑
const App = () => {
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: '张三', age: 20 });
// 复杂计算(模拟耗时操作)
const calculateTotal = () => {
console.log('执行了复杂计算');
let total = 0;
for (let i = 0; i < 100000000; i++) {
total += i;
}
return total;
};
const total = calculateTotal();
// 更新用户年龄的函数
const handleUpdateAge = () => {
setUser(prev => ({ ...prev, age: prev.age + 1 }));
};
return (
<div>
<p>计数器:{count}</p>
<button onClick={() => setCount(c => c + 1)}>增加计数</button>
<p>复杂计算结果:{total}</p>
<UserInfo user={user} onUpdate={handleUpdateAge} />
</div>
);
};
export default App;问题分析:
count 变化会导致 App 重新渲染:calculateTotal 会被重新执行(即使它的结果与 count 无关),浪费性能。UserInfo 组件会重新渲染(因为父组件重新渲染时,user 和 onUpdate 虽然值没变,但 user 是新创建的对象引用,onUpdate 是新创建的函数引用)。useMemo 优化计算结果useMemo 可以缓存计算结果,只有当依赖项变化时才重新计算,避免不必要的重复计算。
import { useState, useMemo, useCallback } from 'react';
// 子组件:用React.memo缓存,避免不必要的重渲染
const UserInfo = React.memo(({ user, onUpdate }) => {
console.log('UserInfo 重新渲染了');
return (
<div>
<p>姓名:{user.name}</p>
<p>年龄:{user.age}</p>
<button onClick={onUpdate}>增长年龄</button>
</div>
);
});
const App = () => {
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: '张三', age: 20 });
// 用useMemo缓存计算结果,依赖项为空数组表示只计算一次
const total = useMemo(() => {
console.log('执行了复杂计算');
let total = 0;
for (let i = 0; i < 100000000; i++) {
total += i;
}
return total;
}, []); // 依赖项为空,只有组件首次渲染时执行
// 用useCallback缓存函数引用,避免每次渲染创建新函数
const handleUpdateAge = useCallback(() => {
setUser(prev => ({ ...prev, age: prev.age + 1 }));
}, []); // 依赖项为空,函数引用不会变化
// 用useMemo缓存对象,避免每次渲染创建新对象
const memoizedUser = useMemo(() => user, [user.age, user.name]);
return (
<div>
<p>计数器:{count}</p>
<button onClick={() => setCount(c => c + 1)}>增加计数</button>
<p>复杂计算结果:{total}</p>
<UserInfo user={memoizedUser} onUpdate={handleUpdateAge} />
</div>
);
};
export default App;useMemo(() => { ... }, []) 缓存了 calculateTotal 的结果,由于依赖项为空数组,该计算只会在组件首次渲染时执行,后续 count 变化不会触发重新计算。React.memo 包装 UserInfo 组件,使其只有在 props 真正变化时才重新渲染。useCallback 缓存 handleUpdateAge 函数,确保每次渲染时函数引用不变(避免因函数引用变化导致子组件重渲染)。useMemo 缓存 user 对象(memoizedUser),只有当 user.name 或 user.age 变化时,才会创建新的对象引用。useMemo 适用于:缓存耗时的计算结果,避免重复计算。React.memo(优化组件)和 useCallback(优化函数)配合,才能彻底解决引用类型 props 导致的冗余渲染。useMemo 本身也有一定的性能开销。通过这些优化,点击“增加计数”按钮时,UserInfo 不会重新渲染,calculateTotal 也不会重新执行,显著提升性能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。