React canvas TypeError:重新渲染后无法读取 null 的属性“getContext”
2021-05-25
5458
我有一个画布,它在引用中使用 canvas.getContext( "2d" )。 我的问题是,当页面重新渲染时,由于状态发生变化,我收到错误,我不知道如何修复它。
这是一个出现错误的最小代码示例:
import React, { useState } from "react";
import { render } from "react-dom";
const Test: React.FC<{}> = () => {
const [ counter, setCounter ] = useState<number>( 0 );
return (
<div>
<button onClick={ () => { setCounter( counter + 1 ) } }>Test</button>
<canvas ref={ canvas => {
let context = canvas.getContext( "2d" );
} }/>
</div>
);
}
render( <Test />, document.getElementById( "root" ) );
这是错误:
canvas_test.component.tsx:11 Uncaught TypeError: Cannot read property 'getContext' of null
at ref (canvas_test.component.tsx:11)
at commitDetachRef (react-dom.development.js:20893)
at commitMutationEffects (react-dom.development.js:23348)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
at invokeGuardedCallback (react-dom.development.js:4056)
at commitRootImpl (react-dom.development.js:23121)
at unstable_runWithPriority (scheduler.development.js:468)
at runWithPriority$1 (react-dom.development.js:11276)
at commitRoot (react-dom.development.js:22990)
为什么会出现这个错误,我该如何修复它?
2个回答
您可以在 useEffect 中初始化画布引用,这样可以在组件挂载或组件更新后立即调用函数。(在画布元素在 dom 中可用之后)
import React, {useState, useEffect, useRef} from "react";
export default function App() {
const [counter, setCounter] = useState(0);
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
const context = canvas.getContext("2d");
}, []);
return (
<div>
<button
onClick={() => {
setCounter(counter + 1);
}}
>
Test
</button>
<canvas ref={canvasRef} />
</div>
);
}
SebMaz
2021-05-25
根据 回调引用 :
React will call the
ref
callback with the DOM element when the component mounts, and call it withnull
when it unmounts .
并且根据 回调引用的注意事项
If the
ref
callback is defined as an inline function, it will get called twice during updates, first withnull
and then again with the DOM element.
我相信您看到的是后者:每次调用
setCounter
都会触发更新,如上所述,它会使用
null
调用您的回调。
解决方案
在您的回调中,处理
null
条件。我建议将回调提取到其自己的函数中。例如:
const Test: React.FC<{}> = () => {
const [ counter, setCounter ] = useState<number>( 0 );
const refHandler = (canvas) => {
if (!canvas) return;
let context = canvas.getContext( "2d" );
}
return (
<div>
<button onClick={ () => { setCounter( counter + 1 ) } }>Test</button>
<canvas ref={refHandler} />
</div>
);
}
rsmeral
2021-05-25