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
相关产品推荐
相关产品推荐

