MST
星途 面试题库

面试题:React复杂场景下逻辑与运算符简洁渲染的性能优化及实践

在一个大型React应用中,存在多层嵌套组件,其中某父组件有一个状态变量isDataLoaded控制数据是否加载完成,子组件根据该状态进行复杂的UI渲染,包括多个不同条件组合下的列表展示、图表渲染等。在这种场景下,使用逻辑与运算符进行简洁渲染可能会带来性能问题,请分析可能出现的性能瓶颈,并提出优化方案,同时给出优化后的关键代码示例。
22.1万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

性能瓶颈分析

  1. 不必要的渲染:当使用逻辑与运算符 (&&) 进行简洁渲染时,每次父组件的 isDataLoaded 状态变化,子组件都会重新渲染。即使子组件中的复杂 UI 渲染(列表展示、图表渲染等)在 isDataLoaded 未变化时不需要更新,也会因为父组件状态变化而重新计算渲染,浪费性能。
  2. 复杂计算重复执行:子组件中复杂 UI 渲染包含多个不同条件组合下的操作,如列表展示和图表渲染可能涉及数据过滤、计算等操作。每次重新渲染都会重复执行这些复杂计算,尤其是在数据量较大时,性能消耗显著。

优化方案

  1. 使用 React.memo:对于子组件,使用 React.memo 包裹,它会对 props 进行浅比较。如果 props 没有变化,子组件不会重新渲染,从而避免不必要的渲染。
  2. shouldComponentUpdate 自定义逻辑:在类组件中,可以重写 shouldComponentUpdate 方法,根据 isDataLoaded 和其他关键数据是否变化来决定是否重新渲染。
  3. Memoization:对于子组件中复杂的计算逻辑(如数据过滤、计算等),可以使用 useMemo(函数组件)或手动缓存计算结果,避免每次渲染都重复计算。

优化后的关键代码示例

函数组件使用 React.memo 和 useMemo

import React, { memo, useMemo } from'react';

// 模拟复杂数据
const data = [/* 大量数据 */];

// 子组件
const ChildComponent = memo(({ isDataLoaded }) => {
  // 使用 useMemo 缓存复杂计算结果
  const filteredData = useMemo(() => {
    // 模拟数据过滤
    return data.filter(item => item.someCondition);
  }, [data]);

  return (
    isDataLoaded && (
      <div>
        {/* 基于 filteredData 进行列表展示 */}
        <ul>
          {filteredData.map(item => (
            <li key={item.id}>{item.value}</li>
          ))}
        </ul>
        {/* 基于 filteredData 进行图表渲染,这里简单示意 */}
        <div>图表渲染区域</div>
      </div>
    )
  );
});

// 父组件
const ParentComponent = () => {
  const [isDataLoaded, setIsDataLoaded] = React.useState(false);

  // 模拟数据加载
  React.useEffect(() => {
    setTimeout(() => {
      setIsDataLoaded(true);
    }, 2000);
  }, []);

  return (
    <div>
      <ChildComponent isDataLoaded={isDataLoaded} />
    </div>
  );
};

export default ParentComponent;

类组件使用 shouldComponentUpdate

import React, { Component } from'react';

// 模拟复杂数据
const data = [/* 大量数据 */];

class ChildComponent extends Component {
  shouldComponentUpdate(nextProps) {
    // 仅当 isDataLoaded 变化时才重新渲染
    return nextProps.isDataLoaded!== this.props.isDataLoaded;
  }

  render() {
    const { isDataLoaded } = this.props;
    // 手动缓存计算结果
    let filteredData = this.filteredData;
    if (!filteredData) {
      filteredData = data.filter(item => item.someCondition);
      this.filteredData = filteredData;
    }

    return (
      isDataLoaded && (
        <div>
          {/* 基于 filteredData 进行列表展示 */}
          <ul>
            {filteredData.map(item => (
              <li key={item.id}>{item.value}</li>
            ))}
          </ul>
          {/* 基于 filteredData 进行图表渲染,这里简单示意 */}
          <div>图表渲染区域</div>
        </div>
      )
    );
  }
}

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isDataLoaded: false
    };
  }

  componentDidMount() {
    setTimeout(() => {
      this.setState({ isDataLoaded: true });
    }, 2000);
  }

  render() {
    const { isDataLoaded } = this.state;
    return (
      <div>
        <ChildComponent isDataLoaded={isDataLoaded} />
      </div>
    );
  }
}

export default ParentComponent;