MST

星途 面试题库

面试题:深度剖析React Fiber架构下的重新渲染机制及优化策略

随着React引入Fiber架构,其重新渲染机制发生了一些变化。请深入分析Fiber架构下的重新渲染过程,包括但不限于任务调度、渲染优先级等方面。结合这种机制,阐述你所知道的避免不必要重新渲染的高级优化策略,以及在大型项目中如何从整体架构层面预防因不合理渲染导致的性能问题。
20.2万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

Fiber架构下的重新渲染过程

  1. 任务调度
    • 任务拆分:Fiber将渲染任务拆分成一个个小的工作单元,即Fiber节点。每个Fiber节点代表一个React元素,包含了该元素的各种信息以及对应的副作用(如DOM更新)。这使得任务可以分段执行,不再是一口气完成整个渲染。
    • 调度算法:使用requestIdleCallback(浏览器空闲时执行任务)或setTimeout(在requestIdleCallback不支持时作为兜底)来调度任务。这样可以优先执行高优先级任务,而将低优先级任务在浏览器空闲时段执行,避免阻塞主线程,保证页面的流畅性。
  2. 渲染优先级
    • 同步任务:如用户交互(点击、输入等)产生的更新,这类任务优先级最高,需要立即处理以保证交互的实时响应。
    • 生命周期任务:如componentDidMountcomponentDidUpdate等,优先级次之。
    • 异步任务:数据获取后引起的更新等,优先级相对较低,可以在浏览器空闲时执行。

避免不必要重新渲染的高级优化策略

  1. 使用React.memo
    • 原理:React.memo是一个高阶组件,用于对函数式组件进行浅比较优化。它会在组件接收到新的props时,对新旧props进行浅比较,如果props没有变化,则不会重新渲染该组件。
    • 示例
const MyComponent = React.memo((props) => {
    return <div>{props.value}</div>;
});
  1. shouldComponentUpdate的优化使用
    • 原理:对于类组件,shouldComponentUpdate方法允许开发者手动控制组件是否需要重新渲染。通过比较新旧props和state,开发者可以决定是否有必要触发重新渲染。
    • 示例
class MyClassComponent extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        return this.props.value!== nextProps.value || this.state.someValue!== nextState.someValue;
    }
    render() {
        return <div>{this.props.value}</div>;
    }
}
  1. Memoization(记忆化)
    • 原理:通过缓存函数的计算结果,避免重复计算。在React中,可以使用useMemouseCallback钩子。useMemo用于缓存值计算结果,useCallback用于缓存函数,避免在每次渲染时重新创建函数,减少不必要的重新渲染。
    • 示例
const expensiveCalculation = (a, b) => {
    // 复杂计算
    return a + b;
};
const MyComponent = () => {
    const result = useMemo(() => expensiveCalculation(1, 2), []);
    const handleClick = useCallback(() => {
        console.log('Button clicked');
    }, []);
    return (
        <div>
            <p>{result}</p>
            <button onClick={handleClick}>Click me</button>
        </div>
    );
};

在大型项目中从整体架构层面预防因不合理渲染导致的性能问题

  1. 合理的组件拆分
    • 原则:将大型组件拆分成多个功能单一、职责明确的小组件。这样每个小组件的渲染逻辑更简单,依赖更少,减少因父组件更新导致不必要子组件重新渲染的概率。
    • 示例:一个复杂的用户信息展示组件,可以拆分为头像组件、基本信息组件、联系方式组件等。
  2. 状态提升
    • 原理:将共享状态提升到最近的共同祖先组件,通过props传递数据给子组件。这样可以避免多个子组件维护相同状态,减少不必要的状态更新和重新渲染。
    • 示例:如果有多个子组件需要使用用户登录状态,将登录状态提升到父组件,通过props传递给需要的子组件。
  3. 使用Redux或MobX等状态管理库
    • 原理:这些库提供了集中式的状态管理,通过严格的状态更新规则和订阅 - 发布模式,使得状态变化可控。并且可以利用其特性(如Redux的reducer纯函数特性),在状态变化时精确控制哪些组件需要重新渲染。
    • 示例:在Redux中,通过定义reducer来处理状态变化,只有订阅了相关状态的组件才会在状态变化时重新渲染。