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

React中创建Phaser 3 GameObject实例时出现重复Canvas组件问题

解决React组件中Phaser Canvas重复的问题

问题原因

你碰到的重复Canvas是因为React严格模式(React.StrictMode)在开发环境下会重复调用componentDidMount,导致你创建了两个Phaser.Game实例,自然生成了两个Canvas。生产环境下StrictMode不会有这个重复执行的行为,但开发阶段会触发这个校验逻辑。

解决方案

方案1:临时移除StrictMode(快速解决)

直接去掉根渲染代码里的<React.StrictMode>包裹,开发环境就不会重复执行生命周期方法了:

root.render(
  <Game />
);

注:StrictMode能帮你提前发现潜在问题,生产环境默认不会启用这个模式,所以这个方法适合快速验证问题根源。

方案2:组件内控制实例只创建一次(规范解法)

在类组件中添加实例变量记录Phaser实例状态,避免重复创建:

import Phaser from "phaser";
import React from "react";

export default class Game extends React.Component {
    private gameInstance: Phaser.Game | null = null;

    componentDidMount() {
        // 仅当实例不存在时才创建
        if (!this.gameInstance) {
            const gameConfig: Phaser.Types.Core.GameConfig = {
                type: Phaser.AUTO,
                parent: 'game-container',
                backgroundColor: '#EBEBEB',
                width: 600,
                height: 800
            }
            this.gameInstance = new Phaser.Game(gameConfig);
        }
    }

    componentWillUnmount() {
        // 组件卸载时销毁实例,避免内存泄漏
        if (this.gameInstance) {
            this.gameInstance.destroy(true);
            this.gameInstance = null;
        }
    }

    shouldComponentUpdate() {
        return false;
    }

    render() {
        return <div id='game-container' />   
    }
}

方案3:转函数组件用useEffect(推荐写法)

换成函数组件,结合useRef标记初始化状态,同时用ref获取容器元素(比id更可靠):

import Phaser from "phaser";
import React, { useEffect, useRef } from "react";

export default function Game() {
    const gameContainerRef = useRef<HTMLDivElement>(null);
    const gameInstanceRef = useRef<Phaser.Game | null>(null);

    useEffect(() => {
        if (!gameInstanceRef.current && gameContainerRef.current) {
            const gameConfig: Phaser.Types.Core.GameConfig = {
                type: Phaser.AUTO,
                parent: gameContainerRef.current,
                backgroundColor: '#EBEBEB',
                width: 600,
                height: 800
            }
            gameInstanceRef.current = new Phaser.Game(gameConfig);
        }

        // 卸载时清理实例
        return () => {
            if (gameInstanceRef.current) {
                gameInstanceRef.current.destroy(true);
                gameInstanceRef.current = null;
            }
        }
    }, []);

    return <div ref={gameContainerRef} />   
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 16:06:42