React canvas TypeError: Cannot read property 'getContext' of null after re-render
React canvas TypeError: Cannot read property 'getContext' of null after re-render
我有一个 canvas,它在参考文献中使用 canvas.getContext( "2d" )。
我的问题是,当页面重新呈现时,bc 状态发生变化,我得到一个错误,我不知道如何修复它。
这是出现错误的最小代码示例:
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 (react-dom.development.js:11276)
at commitRoot (react-dom.development.js:22990)
为什么会出现这个错误,我该如何解决?
React will call the ref
callback with the DOM element when the component mounts, and call it with null
when it unmounts.
并根据 Caveats with callback refs
If the ref
callback is defined as an inline function, it will get called twice during updates, first with null
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>
);
}
您可以在 useEffect 中初始化 canvas 引用,它允许在组件挂载或组件更新后立即调用函数。 (紧接着 canvas 元素在 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>
);
}
我有一个 canvas,它在参考文献中使用 canvas.getContext( "2d" )。 我的问题是,当页面重新呈现时,bc 状态发生变化,我得到一个错误,我不知道如何修复它。
这是出现错误的最小代码示例:
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 (react-dom.development.js:11276)
at commitRoot (react-dom.development.js:22990)
为什么会出现这个错误,我该如何解决?
React will call the
ref
callback with the DOM element when the component mounts, and call it withnull
when it unmounts.
并根据 Caveats with callback refs
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>
);
}
您可以在 useEffect 中初始化 canvas 引用,它允许在组件挂载或组件更新后立即调用函数。 (紧接着 canvas 元素在 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>
);
}