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

React类组件替换useRef操作Canvas时矩形不显示问题求助

问题描述

我正在尝试将React函数组件转换为类组件,转换useRef时使用已废弃的this.refs.canvas触发警告,因此改用React.createRef实现。当前代码运行无报错,但Canvas上绘制的矩形无法在背景图上正常显示,以下是对应的代码:

原函数组件代码

import React, { useRef, useEffect, useState } from "react";
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";

function App() {
  const [data, setData] = useState([]);
  const canvas = useRef();
  let ctx = null;

  // initialize the canvas context
  useEffect(() => {
    // dynamically assign the width and height to canvas
    const canvasEle = canvas.current;
    canvasEle.width = canvasEle.clientWidth;
    canvasEle.height = canvasEle.clientHeight;

    // get context of the canvas
    ctx = canvasEle.getContext("2d");
  }, []);

  const drawRect = (info, style = {}) => {
    const { x, y, w, h } = info;
    const { borderColor = "black", borderWidth = 1 } = style;

    ctx.beginPath();
    ctx.strokeStyle = borderColor;
    ctx.lineWidth = borderWidth;
    ctx.rect(x, y, w, h);
    ctx.stroke();
  };

  const getData = () => {
    fetch("/test.json", {
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    })
      .then(function (response) {
        console.log(response);
        return response.json();
      })
      .then(function (myJson) {
        console.log(myJson.annotations[0].bbox);
        setData(myJson.annotations[1].bbox);
        const x1 = myJson.annotations[2].bbox[0];
        const y1 = myJson.annotations[2].bbox[1];
        const w1 = myJson.annotations[2].bbox[2];
        const h1 = myJson.annotations[2].bbox[3];
        const r1Info = { x: x1, y: y1, w: w1, h: h1 };
        const r1Style = { borderColor: "red", borderWidth: 5 };
        drawRect(r1Info, r1Style);
      });
  };
  useEffect(() => {
    getData();
  }, []);
  // draw rectangle

  return (
    <div className="App">
      <canvas
        style={{
          height: "512px",
          width: "512px",
          backgroundImage: `url(${"https://karthiknbucket1.s3.ap-southeast-1.amazonaws.com/00000002.png"})`,
          backgroundPosition: "center",
          backgroundSize: "100% 100%",
        }}
        ref={canvas}
      ></canvas>
    </div>
  );
}

export default App;

待修正的类组件代码

import React from 'react';
 import './App.css'
import 'bootstrap/dist/css/bootstrap.min.css';
class Apps extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
          
        }
        this.canvas = React.createRef();
      }

    // initialize the canvas context
    componentDidMount() {
      const canvas = this.canvas
      let ctx = null;
      // dynamically assign the width and height to canvas
      const canvasEle = canvas.current;

    
      // get context of the canvas
      ctx = canvasEle.getContext("2d");
      
     const getData=()=>{
      
        fetch('/test.json'
        ,{
          headers : { 
            'Content-Type': 'application/json',
            'Accept': 'application/json'
           }
        }
        )
          .then(function(response){
            console.log(response)
            return response.json();
          })
          .then(function(myJson) {
            console.log(myJson.annotations[0].bbox);
            const x1 = myJson.annotations[2].bbox[0];
            const y1 = myJson.annotations[2].bbox[1];
            const w1= myJson.annotations[2].bbox[2];  
            const h1 = myJson.annotations[2].bbox[3];
            const r1Info = { x:x1 , y:y1, w:w1, h:h1  };
            const r1Style = { borderColor: 'red', borderWidth: 5 };
            drawRect(r1Info, r1Style);
             
          });
          const drawRect = () =>  (info, style = {}) => {
        const { x, y, w, h } = info;
        const { borderColor = 'black', borderWidth = 1 } = style;
     
        ctx.beginPath();
        ctx.strokeStyle = borderColor;
        ctx.lineWidth = borderWidth;
        ctx.rect(x, y, w, h);
        ctx.stroke();
      }
      
      }
      return  getData(); 
    }

  // draw rectangle

 render() {

  return (
    <div className="App">
      
      <canvas style={{height:"512px" ,width:"512px",backgroundImage:`url(${"https://karthiknbucket1.s3.ap-southeast-1.amazonaws.com/00000001.png"})`,
    backgroundPosition:"center",backgroundSize:"100% 100%"
    }} ref={this.canvas}></canvas>

    </div>
    
  );
}
}
 
export default Apps;
问题原因及修正方案

错误点梳理

  • 遗漏了canvas元素实际宽高的赋值:仅在style中设置了canvas的显示尺寸,没有给canvas元素自身的width和height属性赋值,导致绘图坐标系和显示尺寸不匹配,绘制的内容会超出可视区域或缩放变形。
  • drawRect函数定义错误:你写的const drawRect = () => (info, style = {}) => {}是高阶函数,调用drawRect(r1Info, r1Style)时仅会返回内层函数,不会执行绘图逻辑。
  • 函数声明顺序错误:drawRect的定义放在了fetch的then回调之后,调用时变量还未完成初始化。

修正后的完整类组件代码

import React from 'react';
import './App.css'
import 'bootstrap/dist/css/bootstrap.min.css';
class Apps extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      data: []
    }
    this.canvas = React.createRef();
    this.ctx = null;
  }

  drawRect = (info, style = {}) => {
    const { x, y, w, h } = info;
    const { borderColor = 'black', borderWidth = 1 } = style;
    this.ctx.beginPath();
    this.ctx.strokeStyle = borderColor;
    this.ctx.lineWidth = borderWidth;
    this.ctx.rect(x, y, w, h);
    this.ctx.stroke();
  }

  getData = () => {
    fetch('/test.json', {
      headers: { 
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      }
    })
    .then(function(response){
      return response.json();
    })
    .then((myJson) => {
      console.log(myJson.annotations[0].bbox);
      this.setState({data: myJson.annotations[1].bbox});
      const x1 = myJson.annotations[2].bbox[0];
      const y1 = myJson.annotations[2].bbox[1];
      const w1= myJson.annotations[2].bbox[2];  
      const h1 = myJson.annotations[2].bbox[3];
      const r1Info = { x:x1 , y:y1, w:w1, h:h1  };
      const r1Style = { borderColor: 'red', borderWidth: 5 };
      this.drawRect(r1Info, r1Style);
    });
  }

  componentDidMount() {
    const canvasEle = this.canvas.current;
    // 赋值canvas实际宽高,和显示尺寸保持一致
    canvasEle.width = canvasEle.clientWidth;
    canvasEle.height = canvasEle.clientHeight;
    // 初始化上下文挂到实例上,方便调用
    this.ctx = canvasEle.getContext("2d");
    this.getData(); 
  }

  render() {
    return (
      <div className="App">
        <canvas 
          style={{
            height:"512px",
            width:"512px",
            backgroundImage:`url(${"https://karthiknbucket1.s3.ap-southeast-1.amazonaws.com/00000001.png"})`,
            backgroundPosition:"center",
            backgroundSize:"100% 100%"
          }} 
          ref={this.canvas}
        ></canvas>
      </div>
    );
  }
}

export default Apps;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:06:04