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

React中获取id为matrix的canvas元素返回null的问题求助

问题描述

我想给React组件内的canvas添加脚本实现矩阵特效,但执行脚本时,document.getElementById("matrix")返回null,无法获取目标canvas元素。

已尝试的方案

  • 参考方案使用useEffect
  • 将脚本引入移至body标签末尾
  • 替换document.getElementById("matrix")为document.querySelector("#matrix")

相关代码

index.html 的body部分

<body>
    <div id="root" class="has-navbar-fixed-top"></div>
    <script async scr="../src/MatrixEffect/matrix.js"></script>
</body>

matrix.js 脚本代码

window.onload = Init;

function Init() {
  const canvas = document.getElementById("matrix");
  /* const canvas = document.querySelector("#matrix"); */
  console.log(canvas); /* 返回null */
  const context = canvas.getContext("2d");
}

MatrixComponent.js 代码

import styles from "./Matrix.module.css";

const MatrixComponent = () => {
  return (
    <div className={`${styles.container}`}>
      <canvas id="matrix" className={`${styles.canvas}`}></canvas>
    </div>
  );
};

export default MatrixComponent;

报错信息

matrix.js:7 Uncaught TypeError: Cannot read properties of null (reading 'getContext')
at Init (matrix.js:7:1)


问题原因

核心问题是外部脚本的执行时机早于React组件渲染出canvas元素:

  1. window.onload仅等待HTML文档和静态资源加载完成,但React是在#root容器内动态渲染组件,window.onload触发时,MatrixComponent还未完成渲染,canvas元素不存在。
  2. 脚本标签的async属性会让脚本异步加载执行,进一步加大了脚本先于组件渲染的概率。
  3. 额外注意:脚本标签里的scr是拼写错误,正确应为src,这会导致脚本加载失败(若你实际执行了脚本,大概率是笔误)。

解决办法

方案1:将矩阵逻辑移入React组件(推荐,符合React最佳实践)

直接在MatrixComponent中使用useEffect和useRef,确保canvas渲染完成后再执行逻辑:

import { useEffect, useRef } from "react";
import styles from "./Matrix.module.css";

const MatrixComponent = () => {
  // 用useRef获取canvas元素
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    // 判空避免报错
    if (!canvas) return;

    const context = canvas.getContext("2d");
    // 在这里编写你的矩阵特效逻辑,比如初始化、帧绘制等
    console.log("canvas已就绪", canvas);

    // 可选:组件卸载时清理资源,比如取消动画帧
    return () => {
      // cancelAnimationFrame(animationId);
    };
  }, []); // 空依赖数组确保只执行一次

  return (
    <div className={`${styles.container}`}>
      <canvas ref={canvasRef} className={`${styles.canvas}`}></canvas>
    </div>
  );
};

export default MatrixComponent;

这种方式完全贴合React生命周期,代码模块化,无需依赖外部脚本。

方案2:调整外部脚本执行时机(不推荐,非React标准写法)

若坚持使用外部脚本,需确保脚本在React组件渲染完成后执行:

  1. 修正脚本标签的拼写错误:将scr改为src,并移除async属性
<body>
    <div id="root" class="has-navbar-fixed-top"></div>
    <script src="../src/MatrixEffect/matrix.js"></script>
</body>
  1. 修改matrix.js,移除window.onload绑定,将Init暴露到全局:
function Init() {
  const canvas = document.getElementById("matrix");
  if (!canvas) {
    console.error("未找到canvas元素");
    return;
  }
  const context = canvas.getContext("2d");
  // 编写特效逻辑
}

// 暴露到全局,让React入口文件调用
window.Init = Init;
  1. 在React入口文件(如index.js)中,根组件渲染完成后手动调用Init:
import React from 'react';
import ReactDOM from 'react-dom/client';
import MatrixComponent from './MatrixEffect/MatrixComponent';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <MatrixComponent />
  </React.StrictMode>
);

// 根组件渲染完成后执行矩阵初始化
if (window.Init) {
  window.Init();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:39:20