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

ReactJS与NextJS集成ADA Chatbot页面切换初始化问题

解决Next.js/React集成ADA聊天机器人页面切换时窗口关闭的问题

问题背景

在React/Next.js项目中集成ADA聊天机器人,要求仅在A、B页面显示聊天气泡,C页面不加载。但从A页面切换到B页面时,聊天窗口会意外关闭。通过日志发现,B页面的adaEmbed.start()执行完成的时间早于A页面的adaEmbed.stop(),导致A页面的stop操作会关闭已经启动的B页面聊天窗口。

现有代码问题

当前Chat组件在挂载时启动聊天,卸载时直接停止聊天。页面切换时,A组件的卸载逻辑(stop)是异步操作,而B组件的启动逻辑先完成,后续A的stop执行会关闭已启动的聊天窗口。

import { FC, useEffect } from 'react';
import adaEmbed from '@ada-support/embed2';

const Chat: FC<{ caller: string }> = ({ caller }) => {
    useEffect(() => {
        console.log('mounting:', caller);
        adaEmbed
            .start({
                handle: 'HANDLE',
            })
            .then(() => {
                console.log('started:', caller);
            })
        return () => {
            console.log('unmounting:', caller);
            adaEmbed
                .stop()
                .then(() => {
                    console.log('stopped', caller);
                })
        };
    }, [caller]);
    return null;
};

export default Chat;

解决方案

方案1:全局计数器跟踪活跃实例

通过全局计数器跟踪需要显示聊天的页面数量,仅当计数器归0(即所有A/B页面都已卸载,切换到C页面)时才执行stop操作。

修改Chat组件如下:

import { FC, useEffect, useRef } from 'react';
import adaEmbed from '@ada-support/embed2';

// 全局计数器:跟踪当前需要显示聊天的页面实例数
let chatActiveInstances = 0;

const Chat: FC = () => {
  const isChatInitialized = useRef(false);

  useEffect(() => {
    chatActiveInstances++;
    
    // 仅第一次启动聊天,避免重复初始化
    if (!isChatInitialized.current) {
      adaEmbed.start({ handle: 'HANDLE' })
        .then(() => {
          isChatInitialized.current = true;
          console.log('Chat initialized');
        });
    }

    return () => {
      chatActiveInstances--;
      
      // 只有当没有活跃的聊天页面时,才停止聊天
      if (chatActiveInstances === 0) {
        adaEmbed.stop()
          .then(() => {
            isChatInitialized.current = false;
            console.log('Chat stopped');
          });
      }
    };
  }, []);

  return null;
};

export default Chat;

使用方式:

  • 在A、B页面中通过Next.js动态导入并渲染该组件(保持ssr: false确保客户端渲染)
  • C页面不渲染该组件

原理:A→B切换时,A卸载使计数器从1变为0,但同时B挂载使计数器回到1,因此不会触发stop;切换到C时,计数器归0,执行stop关闭聊天窗口。

方案2:路由全局监听控制启停

在Next.js的_app.tsx中监听路由变化,仅当离开A/B页面时执行stop,A/B之间切换不操作。

import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import adaEmbed from '@ada-support/embed2';

function MyApp({ Component, pageProps }) {
  const router = useRouter();
  const [isChatActive, setIsChatActive] = useState(false);

  useEffect(() => {
    // 判断当前页面是否需要显示聊天
    const shouldActivateChat = () => ['/a', '/b'].includes(router.pathname);

    // 初始化时检查状态
    const initialState = shouldActivateChat();
    setIsChatActive(initialState);
    if (initialState) adaEmbed.start({ handle: 'HANDLE' });

    // 路由切换完成后更新状态
    const handleRouteChange = () => {
      const newState = shouldActivateChat();
      if (newState && !isChatActive) {
        adaEmbed.start({ handle: 'HANDLE' });
      } else if (!newState && isChatActive) {
        adaEmbed.stop();
      }
      setIsChatActive(newState);
    };

    router.events.on('routeChangeComplete', handleRouteChange);

    // 页面卸载时清理
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange);
      if (isChatActive) adaEmbed.stop();
    };
  }, [router, isChatActive]);

  return <Component {...pageProps} />;
}

export default MyApp;

原理:直接在全局路由层面控制聊天的启停,A/B之间切换时状态保持为true,不会执行stop操作,避免窗口关闭。

注意事项

  • 确保Chat组件通过Next.js动态导入并设置ssr: false,避免服务端渲染报错:
    import dynamic from 'next/dynamic';
    const Chat = dynamic(() => import('./Chat'), { ssr: false });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:35:18