如何将含构造函数的React Native类组件转为函数组件并解决props问题
解决React Native Game Engine + Matter.js类组件转函数组件的entities未定义问题
问题原因
- 函数组件中最初将
entities设为null,并通过useEffect延迟初始化,导致组件首次渲染时GameEngine拿到的entities是null,进而Physics系统访问entities.physics时触发undefined错误。 - 普通变量
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
相关产品推荐
相关产品推荐

