1

I am importing a third party script into my react application. The third party script is for a chatbot application built with botpress v12. I have made a react component as chatbot and implemented them in the parent page. But the problem is that, this bot is called only in single page or say route, but it is coming in every route. Yes might be because it gets appended in the body of the html, but I need it only in single page and whenever I navigate to another route the chatbot should not be rendered. this is my implementation example.

const BotpressChatbot = () => {
    useEffect(() => {
      const script = document.createElement('script');
      const user = {`enter code here`
        user_profile: getUserFromSession()?.profile.name,
        oidc_User: sessionStorage.getItem(
          `${SESSION_OIDC_TOKEN_KEY}:${AUTHORITY}:${CLIENT}`,
        ),
      };
      var my_data = JSON.stringify(user);
      script.src =
        'https://dev.bot.ask.speciphic.ai/assets/modules/channel-web/inject.js';
      script.addEventListener('load', () => {
        try {
          let config = {
            host: 'https://dev.bot.ask.speciphic.ai',
            botId: 'jllask',
            exposeStore: false,
            startNewConvoOnTimeout: true,
            useSessionStorage: true,
            enableTranscriptDownload: false,
            composerPlaceholder: 'Reply to JLL Ask',
            enableConversationDeletion: true,
            disableNotificationSound: false,
            extraStylesheet:
              'https://dev.bot.ask.speciphic.ai/assets/modules/channel-web/jllAsk.css',
          };

          window.botpressWebChat.init(config);
          window.addEventListener('message', function (event) {
            if (event.data.name && event.data.name == 'webchatReady') {
              window.botpressWebChat.sendEvent({
                type: 'proactive-trigger',
                channel: 'web',
                payload: { text: my_data },
              });
            } else if (
              event.data.payload &&
              event.data.payload.type == 'session_reset'
            ) {
              window.botpressWebChat.sendEvent({
                type: 'proactive-trigger',
                channel: 'web',
                payload: { text: my_data },
              });
            }
          });
        } catch (e) {
          console.log('error in Botpress.jsx', e);
        }
      });
      document.body.appendChild(script);
      return () => {
        document.body.removeChild(script);
      };
    }, []);
    return <></>;
};

export default BotpressChatbot;

in the return statement

return () => {
    document.body.removeChild(script);
  };

if I make the changes like

document.body.removeChild(document.getElementById('bp-web-widget'))

then it works fine, it gets removed from the other routes, and when navigating back to main page the chatbot renders again, but the problem is the script keeps on adding in the body again and again. the way the parent page has been implemented, it renders many times, lots of useEffects are there for the page to work, where it searches and do some operation. Chatbot is a different thing, not related to the working of its parent page. but needed in that page only.

James Z
  • 12,209
  • 10
  • 24
  • 44

1 Answers1

0

It seems like the issue is that the chatbot script is being appended to the body multiple times when the parent page renders multiple times. This behavior can occur if the parent page has multiple useEffect hooks that run when the component mounts or updates. To ensure that the chatbot script is only appended once, you can modify the implementation as follows:

Separate the logic to load the chatbot script into its own useEffect hook with an empty dependency array. This will ensure that the chatbot script is only loaded once when the component mounts.

Move the logic to remove the chatbot script from the body to the cleanup function returned by the useEffect hook that loads the script. This way, when the component unmounts, the script will be removed from the body.

Here's the updated implementation:

import React, { useEffect } from 'react';

const BotpressChatbot = () => {
  useEffect(() => {
    const script = document.createElement('script');
    const user = {
      user_profile: getUserFromSession()?.profile.name,
      oidc_User: sessionStorage.getItem(
        `${SESSION_OIDC_TOKEN_KEY}:${AUTHORITY}:${CLIENT}`
      ),
    };
    var my_data = JSON.stringify(user);
    script.src =
      'https://dev.bot.ask.speciphic.ai/assets/modules/channel-web/inject.js';
    script.addEventListener('load', () => {
      try {
        let config = {
          host: 'https://dev.bot.ask.speciphic.ai',
          botId: 'jllask',
          exposeStore: false,
          startNewConvoOnTimeout: true,
          useSessionStorage: true,
          enableTranscriptDownload: false,
          composerPlaceholder: 'Reply to JLL Ask',
          enableConversationDeletion: true,
          disableNotificationSound: false,
          extraStylesheet:
            'https://dev.bot.ask.speciphic.ai/assets/modules/channel-web/jllAsk.css',
        };

        window.botpressWebChat.init(config);
        window.addEventListener('message', function (event) {
          if (event.data.name && event.data.name === 'webchatReady') {
            window.botpressWebChat.sendEvent({
              type: 'proactive-trigger',
              channel: 'web',
              payload: { text: my_data },
            });
          } else if (
            event.data.payload &&
            event.data.payload.type === 'session_reset'
          ) {
            window.botpressWebChat.sendEvent({
              type: 'proactive-trigger',
              channel: 'web',
              payload: { text: my_data },
            });
          }
        });
      } catch (e) {
        console.log('error in Botpress.jsx', e);
      }
    });

    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
    };
  }, []); // Empty dependency array to run this effect only once when the component mounts

  return <></>;
};

export default BotpressChatbot;

By making these changes, the chatbot script should be loaded only once when the component mounts, and it will be removed from the body when the component unmounts. This should prevent the script from being appended multiple times and avoid the chatbot being rendered on other routes/pages.

  • thank you. But I am already proving an empty dependency array in my code. yes the parent page renders multiple times, it has many useEffect hooks. – Jayanta Basumatary Aug 01 '23 at 05:23