1
- import { createElement , HTMLAttributes , useEffect , useState , VFC } from 'react' ;
1
+ import { HTMLAttributes , useEffect , useRef , useState , VFC } from 'react' ;
2
2
3
3
import { useScript } from '../hooks/useScript' ;
4
4
import { UnityContext } from '../lib/context' ;
@@ -20,7 +20,7 @@ export type UnityRendererProps = Omit<
20
20
* @param {UnityRendererProps } props Configurtion context, Unity-specific
21
21
* callback handlers and default React props for a `HTMLCanvasElement`.
22
22
* Note that `ref` is not available due to internal use.
23
- * @returns {( JSX.Element | null) } A `JSX.Element` containing the renderer,
23
+ * @returns {JSX.Element | null } A `JSX.Element` containing the renderer,
24
24
* or `null` if not initialized yet.
25
25
*/
26
26
export const UnityRenderer : VFC < UnityRendererProps > = ( {
@@ -33,10 +33,9 @@ export const UnityRenderer: VFC<UnityRendererProps> = ({
33
33
const [ ctx , setCtx ] = useState < UnityContext | undefined > ( context ) ;
34
34
const [ loaderState , setLoaderSource ] = useScript ( ctx ?. getConfig ( ) . loaderUrl ) ;
35
35
36
- // We cannot actually render the `HTMLCanvasElement`, so we need the `ref`
37
- // for Unity and a `JSX.Element` for React rendering.
38
- const [ canvas , setCanvas ] = useState < JSX . Element > ( ) ;
39
- const [ renderer , setRenderer ] = useState < HTMLCanvasElement > ( ) ;
36
+ // Reference to the actual <canvas> element, which has to be passed to
37
+ // the native `createUnityInstance()` method.
38
+ const canvas = useRef < HTMLCanvasElement > ( null ) ;
40
39
41
40
// This is the last state the game was in, either ready or not ready.
42
41
// It is used to trigger `onUnityReadyStateChange` reliably.
@@ -104,18 +103,18 @@ export const UnityRenderer: VFC<UnityRendererProps> = ({
104
103
* Unity instance.
105
104
*/
106
105
async function mount ( ) : Promise < void > {
107
- // if no context, renderer or loader is availiable , or the game is already loaded
108
- if ( ! ctx || ! renderer || loaderState !== 'active' || lastReadyState ) {
106
+ // if no context or loader is available , or the game is already loaded
107
+ if ( ! ctx || ! canvas . current || loaderState !== 'active' || lastReadyState ) {
109
108
throw new Error (
110
- 'cannot mount unity instance without a context, loader or renderer '
109
+ 'cannot mount unity instance without a context or loader '
111
110
) ;
112
111
}
113
112
114
113
// get the current loader configuration from the UnityContext
115
114
const c = ctx . getConfig ( ) ;
116
115
117
116
const instance = await window . createUnityInstance (
118
- renderer ,
117
+ canvas . current ,
119
118
{
120
119
dataUrl : c . dataUrl ,
121
120
frameworkUrl : c . frameworkUrl ,
@@ -171,21 +170,9 @@ export const UnityRenderer: VFC<UnityRendererProps> = ({
171
170
}
172
171
} , [ loaderState ] ) ;
173
172
174
- // on mount
175
- useEffect ( ( ) => {
176
- // create the renderer and let the ref callback set its handle
177
- setCanvas (
178
- createElement ( 'canvas' , {
179
- ref : ( r : HTMLCanvasElement ) => setRenderer ( r ) ,
180
- ...canvasProps ,
181
- } )
182
- ) ;
183
-
184
- // on unmount
185
- return ( ) => {
186
- unmount ( ) ;
187
- } ;
188
- } , [ ] ) ;
173
+ // on unmount
174
+ useEffect ( ( ) => ( ) => unmount ( ) , [ ] ) ;
189
175
190
- return canvas || null ;
176
+ // eslint-disable-next-line react/jsx-props-no-spreading
177
+ return < canvas { ...canvasProps } ref = { canvas } /> ;
191
178
} ;
0 commit comments