Search code examples
javascriptreactjsionic-frameworkcapacitorcapacitor-plugin

Ionic Capacitor App eventlistner plugin called multiple times in a single click


I am using Ionic capacitor to build my reactjs Web application. I have added a Capacitor App Apis to get the back event capture in my App.js file like this,

APPS.addListener("backButton", () => {
    if (renderedScreenUIList.length === 0) {
      // APPS.exitApp();
      alert("exit app");
    } else {
      alert("previous screen");
    }
  });

But when i press back button this back event is called 3 times instead of one. my App.js file is.

// import "./StyleSeets/LightTheme.css";
import "./StyleSeets/theme.css";
import "./App.css";
import React, { useEffect, useState } from "react";
import Drawer from "@mui/material/Drawer";
import { App as APPS } from "@capacitor/app";
import Login from "./Components/Login";
import ERPUtils from "./Components/ERPUtils";
import Main from "./Components/Main";

// ************************** back fire event handling ****************
const renderedScreenUIList = [];

function App() {
  // const [ stylePath, setStylePath ] = useState("./StyleSeets/LightTheme.css");
  const [renderPageType, setRenderPageType] = useState("login");
  const [isMobileView, setIMobileView] = useState(window.innerWidth < 920);
  const isConsoleOpen = false;

  window.onresize = function () {
    console.log(window.outerHeight - window.innerHeight);
    if ((window.outerHeight - window.innerHeight) > 100) { console.log("open"); } else console.log("close");
  };
  const themeList = [
    { value: "#2776ed", label: "light" },
    { value: "#45b11c", label: "nature" },
    { value: "#2AB67B", label: "evening" },
    { value: "#add8e6", label: "sky" },
    { value: "#2b035b", label: "dark" }];
  const languageList = [
    { value: "ENG", label: "English" },
    { value: "MAL", label: "മലയാളം" },
    { value: "HIND", label: "हिन्दी" }];
  const [language, setLanguage] = useState("ENG");
  const onThemeChangeCall = () => {
    const themeName = sessionStorage.getItem("theme-name");
    const themeElement = document.getElementById("app-theme");
    themeElement.className = "App";
    document.documentElement.setAttribute("data-theme", themeName);
  };

  APPS.addListener("backButton", () => {
    if (renderedScreenUIList.length === 0) {
      // APPS.exitApp();
      alert("exit app");
    } else {
      alert("previous screen");
    }
  });

  const languageChanged = (type) => {
    setLanguage(type);
  };

  useEffect(() => {
    onThemeChangeCall();
  }, []);

  const changePage = (page) => {
    setRenderPageType(page);
  };

  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
  const changeTheme = (type) => {
    sessionStorage.setItem("theme-name", type);
    document.documentElement.classList.add("color-theme-in-transition");
    window.setTimeout(() => {
      document.documentElement.classList.remove("color-theme-in-transition");
    }, 1000);
    onThemeChangeCall();
  };

  const toggleDrawer = (value) => {
    setIsSettingsOpen(value);
  };

  const changeLanguage = (type) => {
    sessionStorage.setItem("language-theme", type);
    languageChanged(type);
  };

  useEffect(() => {
    setIMobileView(window.innerWidth < 920);
  }, [window.innerWidth]);

  return (
    <div className="App" id="app-theme">

      {renderPageType === "login"
        ? (
          <Login
            onThemeChangeCall={onThemeChangeCall}
            changePage={changePage}
            languageChanged={languageChanged}
            toggleDrawer={toggleDrawer}
          />
        )
        : null}
      {renderPageType === "home"
        ? (
          <Main
            onThemeChangeCall={onThemeChangeCall}
            changePage={changePage}
            languageChanged={languageChanged}
            toggleDrawer={toggleDrawer}
            isMobileView={isMobileView}
          />
        )
        : null}
      <Drawer
        anchor="right"
        open={isSettingsOpen}
        onClose={() => toggleDrawer(false)}
      >
        <div className="p-2 " style={{ width: "250px", backgroundColor: "var(--primaryBackground)" }}>
          <h6 className="border-bottom p-2">Themes</h6>
          <div className="">
            {!ERPUtils.isNullorWhiteSpace(themeList) ? themeList.map((el, index) => (
              <div
                key={index}
                onKeyDown={(e) => {
                  if (ERPUtils.isKeyBoardEnterPressed(e)) {
                    changeTheme(el.label);
                  }
                }}
                role="button"
                tabIndex={0}
                className="p-2 d-flex align-items-center font-2 justify-content-start"
                onClick={() => changeTheme(el.label)}
              >
                <span className="theme-thumbnail" style={{ backgroundColor: el.value }} />
                <span>{(`${el.label}`).toLocaleUpperCase()}</span>
              </div>
            )) : null}
          </div>
        </div>
        <div className="p-2" style={{ width: "250px", backgroundColor: "var(--primaryBackground)" }}>
          <h6 className="border-bottom p-2">Language</h6>
          <div className="">
            {!ERPUtils.isNullorWhiteSpace(languageList) ? languageList.map((el, index) => (
              <div
                key={index}
                onKeyDown={(e) => {
                  if (ERPUtils.isKeyBoardEnterPressed(e)) {
                    changeLanguage(el.value);
                  }
                }}
                role="button"
                tabIndex={0}
                className="p-2 d-flex align-items-center font-2 justify-content-start"
                onClick={() => changeLanguage(el.value)}
              >
                <span className="language-thumbnail">{el?.label.split("")[0]}</span>
                <span>{(`${el.label}`).toLocaleUpperCase()}</span>
              </div>
            )) : null}
          </div>
        </div>
      </Drawer>
      {/* <ThemeSwitcherProvider defaultTheme="light" themeMap={themes}> */}
      {/* <link rel="stylesheet" type="text/css" href={stylePath} />      */}

      {/* </ThemeSwitcherProvider> */}
    </div>
  );
}

export default App;

Kindly suggest a solution for this problem ?. If I call this event listener outside App.js file it only calls once.


Solution

  • With each page reload the listener is added again. To fix this you should call removeAllListeners() => Promise<void> once at the beginning:

    App.removeAllListeners().then(() => {
      App.addListener("backButton", () => {
        if (renderedScreenUIList.length === 0) {
          // APPS.exitApp();
          alert("exit app");
        } else {
          alert("previous screen");
        }
      });
    });