React中使用requestIdleCallback优化大量数据渲染?

如何在react中使用requestIdleCallback来实现大量数据的渲染优化?

image.png
目前通过这种方式处理之后最后一组数据屏幕一直闪烁,请教一下大佬们。
这里只是测试的数据,之所以没采用虚拟列表是因为真实数据中的每一项的高度不固定,虚拟列表处理起高度计算有点复杂。

阅读 865
avatarAI BotBETA

React 中使用 requestIdleCallback 可以帮助优化大量数据的渲染,特别是在浏览器空闲时执行高优先级的渲染任务。requestIdleCallback 是一个浏览器提供的 API,它允许你在主线程空闲时执行后台或低优先级的任务。

要在 React 中使用 requestIdleCallback 来优化大量数据的渲染,你可以按照以下步骤进行:

  1. 创建一个处理函数:这个函数将负责渲染你的数据。它应该接受一个 deadline 对象作为参数,这个对象包含了一个 timeRemaining 方法,可以用来检查还剩下多少可用的空闲时间。
function handleIdle(deadline) {
  const startTime = performance.now();

  // 渲染数据的逻辑
  renderData();

  const usedTime = performance.now() - startTime;

  // 如果还有剩余时间,请求下一个空闲回调
  if (deadline.timeRemaining() > usedTime) {
    requestIdleCallback(handleIdle);
  }
}
  1. 在组件中调用 requestIdleCallback:在你的 React 组件中,当需要渲染大量数据时,调用 requestIdleCallback 并传入你的处理函数。
class MyComponent extends React.Component {
  componentDidMount() {
    if ('requestIdleCallback' in window) {
      window.requestIdleCallback(this.handleIdle);
    }
  }

  handleIdle = (deadline) => {
    // 渲染数据的逻辑
    this.renderData();

    const usedTime = performance.now() - deadline.timeRemaining();

    // 如果还有剩余时间,请求下一个空闲回调
    if (deadline.timeRemaining() > usedTime) {
      window.requestIdleCallback(this.handleIdle);
    }
  };

  renderData() {
    // 渲染你的数据
  }

  render() {
    // 渲染你的组件
  }
}
  1. 处理数据渲染:在 renderData 函数中,根据你的数据渲染组件。你可能需要分批处理数据,以便在浏览器空闲时逐步渲染。
renderData() {
  // 假设 this.props.data 是你要渲染的数据
  const batchSize = 100; // 你可以根据需要调整这个值
  for (let i = 0; i < this.props.data.length; i += batchSize) {
    const end = Math.min(i + batchSize, this.props.data.length);
    this.setState({ renderedData: this.props.data.slice(i, end) });
  }
}
  1. 处理组件卸载:在组件卸载时,确保取消任何待处理的 requestIdleCallback
componentWillUnmount() {
  if ('cancelIdleCallback' in window) {
    window.cancelIdleCallback(this.handleIdle);
  }
}

关于你提到的屏幕闪烁问题,这可能是由于数据渲染时引起的重渲染。你可以尝试以下方法来解决:

  • 使用 shouldComponentUpdateReact.memo:通过阻止不必要的重渲染来优化性能。
  • 使用 CSS 动画或过渡:如果闪烁是由于元素突然出现在屏幕上,考虑使用 CSS 动画或过渡来平滑地显示元素。
  • 优化渲染逻辑:确保你的渲染逻辑尽可能高效,避免在每次渲染时执行昂贵的操作。

由于你没有提供具体的代码和屏幕闪烁的具体细节,以上建议可能需要根据你的实际情况进行调整。

1 个回答
const usePerformTask = <T>(data: T[], run: (batch: T[]) => void, batchSize = 10) => {
  const dataRef = useRef(data);
  useEffect(() => {
    dataRef.current = data;
  }, [data]);

  useEffect(() => {
    let isCancelled = false;
    const performTask = (deadline: IdleDeadline) => {
      while (!isCancelled && dataRef.current.length > 0 && deadline.timeRemaining() > 0) {
        const batch = dataRef.current.splice(0, batchSize);
        run(batch);
      }

      if (!isCancelled && dataRef.current.length > 0) {
        requestIdleCallback(performTask);
      }
    };
    requestIdleCallback(performTask);

    return () => {
      isCancelled = true;
    };
  }, [batchSize]);
};

简单的自定义一个hooks来解决这个问题。
大量数据分片渲染,可以使用deadline.timeRemaining这个方法来判断当前帧是否还有时间做任务。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题