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

如何将含构造函数的React Native类组件转为函数组件并解决props问题

解决React Native Game Engine + Matter.js类组件转函数组件的entities未定义问题

问题原因

  1. 函数组件中最初将entities设为null,并通过useEffect延迟初始化,导致组件首次渲染时GameEngine拿到的entities是null,进而Physics系统访问entities.physics时触发undefined错误。
  2. 普通变量gameEngine在组件重渲染时会被重置,无法正确保存GameEngine实例引用。

修正后的完整函数组件代码

import React, { useState, useRef } from 'react';
import Matter from "matter-js";
import { GameEngine } from "react-native-game-engine";

export default function GameApp() {
    const [running, setRunning] = useState(true);
    const [score, setScore] = useState(0);
    const gameEngineRef = useRef(null); // 用useRef保存GameEngine实例
    const [entities, setEntities] = useState(() => setupWorld()); // 初始化时直接创建entities

    const setupWorld = () => {
        let engine = Matter.Engine.create({ enableSleeping: false });
        let world = engine.world;
        world.gravity.y = 0.0;

        let bird = Matter.Bodies.rectangle(Constants.MAX_WIDTH / 2, Constants.MAX_HEIGHT / 2, Constants.BIRD_WIDTH, Constants.BIRD_HEIGHT);

        let floor1 = Matter.Bodies.rectangle(
            Constants.MAX_WIDTH / 2,
            Constants.MAX_HEIGHT - 25,
            Constants.MAX_WIDTH + 4,
            50,
            { isStatic: true }
        );

        let floor2 = Matter.Bodies.rectangle(
            Constants.MAX_WIDTH + (Constants.MAX_WIDTH / 2),
            Constants.MAX_HEIGHT - 25,
            Constants.MAX_WIDTH + 4,
            50,
            { isStatic: true }
        );

        Matter.World.add(world, [bird, floor1, floor2]);
        Matter.Events.on(engine, 'collisionStart', (event) => {
            // 通过ref的current访问GameEngine实例
            gameEngineRef.current?.dispatch({ type: "game-over" });
        });

        return {
            physics: { engine: engine, world: world },
            floor1: { body: floor1, renderer: Floor },
            floor2: { body: floor2, renderer: Floor },
            bird: { body: bird, pose: 1, renderer: Bird },
        };
    };

    const onEvent = (e) => {
        if (e.type === "game-over") {
            setRunning(false);
        } else if (e.type === "score") {
            // 函数式更新避免闭包问题
            setScore(prevScore => prevScore + 1);
        }
    };

    const reset = () => {
        resetPipes();
        const newEntities = setupWorld();
        gameEngineRef.current?.swap(newEntities);
        setEntities(newEntities);
        setRunning(true);
        setScore(0);
    };

    return (
        <View style={/* 你的样式 */}>
            <GameEngine
                ref={gameEngineRef}
                entities={entities}
                onEvent={onEvent}
                systems={[Physics /* 你的其他系统 */]}
                running={running}
            />
            {/* 你的其他UI元素,比如分数显示、重置按钮 */}
        </View>
    );
}

关键修改说明

  • 用useRef保存GameEngine实例:普通变量在组件重渲染时会被重新声明,useRef能持久保存可变引用,确保事件回调和reset函数能正确访问GameEngine实例。
  • 初始化时直接创建entities:通过useState的初始化函数直接调用setupWorld(),确保组件首次渲染时GameEngine就能拿到完整的entities对象,避免Physics系统拿到undefined。
  • 事件回调中使用ref访问GameEngine:gameEngineRef.current确保能获取到最新的GameEngine实例。
  • 分数的函数式更新:避免闭包导致的分数更新错误,确保每次更新都基于最新的状态值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 04:14:57