MST

星途 面试题库

面试题:React长列表虚拟化中的性能优化点

在实现React长列表虚拟化时,除了基本的可见区域渲染,还有哪些性能优化点需要考虑?比如如何处理列表项的动态高度、如何优化数据更新时的渲染性能。
33.1万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

处理列表项的动态高度

  1. 测量并缓存高度 在渲染列表项之前,测量每个列表项的高度,并将其缓存起来。可以在数据加载阶段或者首次渲染时进行测量。例如,使用ref来获取列表项元素的实际高度:
import React, { useRef } from'react';

const Item = ({ data }) => {
  const itemRef = useRef(null);
  const measureHeight = () => {
    if (itemRef.current) {
      const height = itemRef.current.offsetHeight;
      // 这里可以将height存储到一个全局或者组件状态中
    }
  };
  React.useEffect(() => {
    measureHeight();
  }, []);
  return <div ref={itemRef}>{data}</div>;
};
  1. 使用自适应高度算法 有些虚拟化库支持动态高度算法,如react - virtualizedAutoSizer组件结合List组件。AutoSizer会自动测量父容器的尺寸,List组件则根据这些尺寸和列表项的高度计算可见区域。

优化数据更新时的渲染性能

  1. 使用shouldComponentUpdateReact.memo 对于类组件,通过重写shouldComponentUpdate方法,根据数据变化情况决定是否重新渲染。例如:
class MyListItem extends React.Component {
  shouldComponentUpdate(nextProps) {
    return this.props.data!== nextProps.data;
  }
  render() {
    return <div>{this.props.data}</div>;
  }
}

对于函数组件,使用React.memo进行浅比较优化。只有当组件的props发生变化时才重新渲染:

const MyListItem = React.memo(({ data }) => {
  return <div>{data}</div>;
});
  1. 批量更新 在React中,数据更新可能会导致多次渲染。可以使用unstable_batchedUpdates(React 18之前)或者React 18自动批量更新机制,将多个状态更新合并为一次渲染。例如:
import React, { useState, useEffect } from'react';
import ReactDOM from'react-dom';
import { unstable_batchedUpdates } from'react-dom';

const App = () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  const handleClick = () => {
    // React 18之前使用unstable_batchedUpdates
    // unstable_batchedUpdates(() => {
    //   setCount1(count1 + 1);
    //   setCount2(count2 + 1);
    // });
    // React 18自动批量更新
    setCount1(count1 + 1);
    setCount2(count2 + 1);
  };
  return (
    <div>
      <p>Count1: {count1}</p>
      <p>Count2: {count2}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
  1. 使用useCallbackuseMemo useCallback用于缓存函数,避免在每次渲染时重新创建,从而减少不必要的子组件重新渲染。例如:
const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);
  return <Child onClick={handleClick} />;
};

const Child = React.memo(({ onClick }) => {
  return <button onClick={onClick}>Click me</button>;
});

useMemo用于缓存计算结果,只有当依赖项发生变化时才重新计算。比如:

const Parent = () => {
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);
  const result = useMemo(() => {
    return a + b;
  }, [a, b]);
  return <div>{result}</div>;
};