You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在memoizedTodos渲染到屏幕后执行handleOpen函数?

实现方案

要在memoizedTodos对应的大量内容(包括文本、图片)完全显示在屏幕后执行handleOpen,核心是要等DOM渲染完成+所有异步资源(如图片)加载完毕,以下是几种可行方案:

方案一:纯DOM元素(无异步资源)

如果memoizedTodos里只有文本、普通DOM元素,没有图片这类需要异步加载的资源,可以用useEffect结合requestAnimationFrame:

import React, { useMemo, useEffect } from "react";
import "./styles.css";

export default function App() {
  const handleOpen = () => {
    console.log("this is running");
  };

  const memoizedTodos = useMemo(() => {
    return [...Array(1000)].map((e, i) => <li key={i}>This is so many data</li>);
  }, []);

  useEffect(() => {
    // requestAnimationFrame会等待浏览器完成下一次重绘后执行
    const rafId = requestAnimationFrame(() => {
      handleOpen();
    });
    return () => cancelAnimationFrame(rafId);
  }, [memoizedTodos]); // 依赖memoizedTodos,确保内容更新后重新触发

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <>{memoizedTodos}</>
    </div>
  );
}

useEffect会在组件DOM更新完成后触发,而requestAnimationFrame会等待浏览器把更新后的DOM绘制到屏幕上,此时内容已经可见,适合纯同步渲染的场景。

方案二:包含图片等异步资源

如果memoizedTodos里有图片,必须等所有图片加载完成后内容才会完全显示,这时候需要监听所有图片的load事件:

import React, { useMemo, useEffect, useRef } from "react";
import "./styles.css";

export default function App() {
  const handleOpen = () => {
    console.log("this is running");
  };
  const todosContainerRef = useRef(null);

  const memoizedTodos = useMemo(() => {
    return [...Array(1000)].map((e, i) => (
      <li key={i}>
        This is so many data
        <img src={`https://picsum.photos/200/200?random=${i}`} alt={`todo-${i}`} />
      </li>
    ));
  }, []);

  useEffect(() => {
    const container = todosContainerRef.current;
    if (!container) return;

    const images = container.querySelectorAll("img");
    if (images.length === 0) {
      // 没有图片,直接执行
      requestAnimationFrame(handleOpen);
      return;
    }

    // 用Promise等待所有图片加载完成
    const imageLoadPromises = Array.from(images).map(img => {
      // 如果图片已经加载完成,直接返回resolved Promise
      if (img.complete) return Promise.resolve();
      return new Promise(resolve => {
        img.addEventListener("load", resolve, { once: true });
        // 处理图片加载失败的情况,避免一直等待
        img.addEventListener("error", resolve, { once: true });
      });
    });

    (async () => {
      await Promise.all(imageLoadPromises);
      // 所有图片加载完成后,等待重绘
      requestAnimationFrame(handleOpen);
    })();
  }, [memoizedTodos]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <div ref={todosContainerRef}>{memoizedTodos}</div>
    </div>
  );
}

这里用Promise.all监听所有图片的加载状态,等全部加载(或失败)后,再通过requestAnimationFrame确保内容绘制到屏幕上,最后执行handleOpen。

关于async/await的使用

async/await适合用来处理异步资源加载的场景(比如方案二中的图片加载),把异步等待的逻辑变得更清晰,但它本身不能直接监听DOM渲染完成——必须结合useEffect和requestAnimationFrame来配合使用,才能确保内容完全可见后执行回调。

内容的提问来源于stack exchange,提问作者Happy1234

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:15:32