面试题答案
一键面试关注的关键指标
- 渲染时间:在 React DevTools 的 Profiler 标签中,可以看到每个组件的渲染时间。长时间的渲染会导致页面卡顿,影响用户体验。如果某个组件渲染时间明显高于其他组件,那它很可能是性能瓶颈。
- 重渲染频率:在 React DevTools 中,能观察到组件重渲染的次数。不必要的重渲染会浪费性能。例如,一个纯展示组件频繁重渲染,就需要检查其依赖的状态或 props 是否不合理地发生了变化。
- 内存占用:使用浏览器的性能分析工具(如 Chrome DevTools 的 Memory 面板),结合 React DevTools。过高的内存占用可能导致页面缓慢甚至崩溃,若发现内存持续增长且不释放,说明存在内存泄漏,这可能与组件的生命周期管理不当有关。
针对性的组件树优化
- 针对渲染时间长
- 使用 React.memo 或 PureComponent:对于函数式组件,使用 React.memo 包裹,类组件继承 PureComponent。它们会在 props 没有变化时,跳过不必要的渲染。例如,如果一个展示用户信息的组件,只要用户信息不变,就不应重新渲染。
const UserInfo = React.memo(({ user }) => { return <div>{user.name}</div>; });
- 拆分组件:将大组件拆分成小组件,每个小组件只负责自己的渲染逻辑,减少单个组件的渲染负担。例如,一个复杂的表单组件,可以拆分成输入框、下拉框等多个小组件。
- 针对重渲染频率高
- 优化状态管理:确保状态提升到合适的层级,避免不必要的状态变化传递到子组件。例如,如果某个子组件只依赖于部分全局状态,就通过 redux 的 selector 等方式,只传递该部分状态,减少不必要的重渲染。
- 使用 useCallback 和 useMemo:在函数式组件中,useCallback 可以缓存函数,避免每次渲染都创建新的函数,从而防止因函数引用变化导致子组件不必要的重渲染。useMemo 缓存值,例如缓存复杂计算的结果,只有依赖项变化时才重新计算。
const handleClick = useCallback(() => { // 处理点击逻辑 }, []); const expensiveValue = useMemo(() => { // 复杂计算 return result; }, [dependency]);
- 针对内存占用高
- 正确处理组件生命周期:在类组件中,确保在 componentWillUnmount 中清除定时器、取消网络请求等操作,防止内存泄漏。例如:
class MyComponent extends React.Component { componentWillUnmount() { clearInterval(this.timer); } componentDidMount() { this.timer = setInterval(() => { // 定时任务 }, 1000); } render() { return <div>My Component</div>; } }
- 避免过度创建对象:在组件渲染过程中,尽量复用对象,而不是每次渲染都创建新的对象。例如,不要在 render 方法中创建新的数组或对象作为 props 传递给子组件。