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

在Next.js中注册A-Frame自定义组件报错的解决方案咨询

如何在Next.js中正确使用A-Frame并避免组件重复注册错误

问题背景

我尝试使用A-Frame结合Next.js创建VR场景,想要注册一个带有点击事件的自定义A-Frame组件,编写的代码如下:

import type { NextPage } from 'next';

import React, { useEffect, useState } from 'react';
import {
  Scene,
  Box,
  Sky,
  Entity,
  Assets
} from '@belivvr/aframe-react';

const Home: NextPage = () => {
  const [rendered, setRendered] = useState<boolean>(false);


  function register() {
    AFRAME.registerComponent('foo', {
      events: {
        click: function (evt: any) {
          console.log('This entity was clicked!');
        }
      }
    });
  }


  useEffect(() => {
    setRendered(true);
    if (typeof window !== 'undefined') {
      require('aframe');
      register();
    }
  }, [setRendered]);

  if (!rendered) {
    return <>loading</>;
  }

  return (
    <Scene>
      <Assets>
        <img id="sky" src="https://cdn.glitch.com/c52283d6-3489-44e4-b56b-43550d1bc76c%2F1.jpg?v=1564408735128" alt="sky" />
        <img id="hotspot" src="https://cdn.glitch.com/c52283d6-3489-44e4-b56b-43550d1bc76c%2Fhotspot.png?v=1564471993959" />
      </Assets>
      <Box
        foo
        position={{ x: -1, y: 0.5, z: -3 }}
        rotation={{ x: 0, y: 45, z: 0 }}
        color="#4CC3D9"
      />
      <Entity>
        <Sky className="sky" src="#sky" rotation={{ x: 0, y: 0, z: 0 }} />
      </Entity>

    </Scene>
  );
};

export default Home;

运行错误

运行时出现如下错误:

Unhandled Runtime Error
Error: The component `foo` has been already registered. Check that you are not loading two versions of the same component or two different components of the same name.

解决方案

1. 注册前检查组件是否已存在

Next.js的热重载或组件重复渲染会导致AFRAME.registerComponent被多次调用,注册前先校验组件是否存在:

function register() {
  // 先判断组件是否已注册,避免重复注册
  if (!AFRAME.components.foo) {
    AFRAME.registerComponent('foo', {
      events: {
        click: function (evt: any) {
          console.log('This entity was clicked!');
        }
      }
    });
  }
}

2. 优化useEffect的依赖项

原代码中useEffect依赖setRendered,会导致状态更新时重复触发effect。改为空数组,确保只在组件挂载时执行一次:

useEffect(() => {
  setRendered(true);
  if (typeof window !== 'undefined') {
    require('aframe');
    register();
  }
}, []); // 空数组表示仅在组件挂载时执行

3. 避免重复引入A-Frame

可以将A-Frame的引入逻辑优化,比如在Next.js的public/index.html中通过script标签直接引入A-Frame,避免在useEffect中重复require:

<!-- public/index.html -->
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>

这样就不需要在组件中require('aframe'),直接使用全局的AFRAME对象即可。

4. 可选:使用Next.js动态导入禁用SSR

A-Frame是基于浏览器的库,服务器端渲染时可能会有问题,可使用Next.js的动态导入禁用SSR:

import dynamic from 'next/dynamic';

// 动态导入A-Frame场景组件,禁用服务器端渲染
const AFrameScene = dynamic(() => import('./AFrameScene'), { ssr: false });

const Home: NextPage = () => {
  return <AFrameScene />;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:25:48