
当父组件因状态变化而重渲染时,即使子组件接收的 props 未改变,它默认仍会重新渲染;使用 React.memo 可以让子组件跳过不必要的重渲染,前提是其 props 是浅层稳定的。
当父组件因状态变化而重渲染时,即使子组件接收的 props 未改变,它默认仍会重新渲染;使用 `react.memo` 可以让子组件跳过不必要的重渲染,前提是其 props 是浅层稳定的。
在 React 中,父组件重渲染会触发所有子组件的默认重渲染流程,无论子组件的 props 是否真正发生变化。这正是你遇到问题的根本原因:App 组件中 anotherProp 的更新导致整个组件重渲染,进而使 也被重新挂载和渲染——尽管 title 和 handleInputChange 这两个 props 实际上并未改变(得益于 useCallback 的缓存),但 React 默认不进行 props 差异比对。
要解决这个问题,需显式告诉 React:“若 ChildComponent 的 props 未发生浅层变化,请跳过本次渲染”。这正是 React.memo 的职责:
// ChildComponent.jsx
import { memo } from 'react';
function ChildComponent({ title, handleInputChange }) {
console.log("Child Component renders"); // 仅在 props 变化时打印
return (
<input type="text" onchange="{handleInputChange}"><h1>{title}</h1>
>
);
}
export default memo(ChildComponent); // ✅ 关键:包裹 memo
同时,建议优化 App.js 中的 useCallback 依赖项:
-
handleInputChange回调内部只调用setPageTitle(e.target.value),并未读取pageTitle当前值,因此将其从依赖数组中移除,避免无效闭包捕获和潜在的重复绑定:
const handleInputChange = useCallback( (e) => setPageTitle(e.target.value), [] // ✅ 改为空数组,更安全且高效 ); const handleIncrement = useCallback( () => setAnotherProp(prev => prev + 1), // ✅ 推荐使用函数式更新,避免依赖 [anotherProp] [] );
⚠️ 注意事项:
-
React.memo仅执行 props 的浅层比较(shallow comparison)。若传入对象、数组或函数引用频繁重建(如内联函数、字面量对象),仍会触发重渲染; - 不要滥用
memo:对简单、无性能瓶颈的组件加memo可能增加比对开销,得不偿失; -
memo不影响组件内部状态或useEffect等副作用逻辑,它仅控制是否跳过render阶段; - 若需深度比较或自定义比对逻辑,可传入第二个参数:
memo(Component, (prevProps, nextProps) => {...})。
总结:useCallback 解决的是函数引用稳定性问题,而 React.memo 解决的是子组件渲染决策问题,二者常配合使用,但职责分明。只有两者协同,才能真正实现“props 不变 → 子组件不渲染”的预期行为。











