1

I'm trying to integrate Firebase to React using React Context. The React project uses the Able template. When I wrap my App component with ContextProvider, it causes an infinite loop.

Here is the code: ./Firebase/firebase.js

import React, { createContext } from "react";
import { useDispatch } from "react-redux";

import firebaseConfig from "./firebaseConfig";
import app from "firebase/app";
import 'firebase/auth';
import 'firebase/firestore';
import "firebase/database";

import { setLoggedUser } from '../store/actions'

// we create a React Context, for this to be accessible
// from a component later
const FirebaseContext = createContext(null);
export { FirebaseContext };

export default ({ children }) => {
   let firebase = {
      app: null,
      database: null,
   };

   const dispatch = useDispatch();

   // check if firebase app has been initialized previously
   // if not, initialize with the config we saved earlier
   if (!app.apps.length) {      
      app.initializeApp(firebaseConfig);
      firebase = {
         app: app,
         database: app.database(),

         api: {
            getUserProfile,
         },
      };
   }   

   // function to query logged user from the database and
   // fire a Redux action to update the items in real-time
   function getUserProfile() {
      ....
      }
   };

   return <FirebaseContext.Provider value={firebase}>{children}</FirebaseContext.Provider>;
};

./index.js

import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";

import App from "./App/index";
import * as serviceWorker from "./serviceWorker";
import reducer from "./store/reducer";
import config from "./config";

import "./assets/scss/style.scss";
import FirebaseProvider from './Firebase/firebase.js';

const store = createStore(reducer);

const app = (
   <Provider store={store}>
      <BrowserRouter basename={config.basename}>
         <FirebaseProvider> <----- cause infinite loading
            <App />
         </FirebaseProvider>
      </BrowserRouter>
   </Provider>
);

ReactDOM.render(app, document.getElementById("root"));

The source code that causes the error is where the loadable import component AdminLayout in App/index.js ./App/index.js

import React, { Component, Suspense } from "react";
import { Switch, Route } from "react-router-dom";
import Loadable from "react-loadable";

import "../../node_modules/font-awesome/scss/font-awesome.scss";

import Loader from "./layout/Loader";
import Aux from "../hoc/_Aux";
import ScrollToTop from "./layout/ScrollToTop";
import routes from "../route";

import { FirebaseContext } from '../Firebase/firebase.js';

const AdminLayout = Loadable({
  loader: () => {
    debugger
    return import("./layout/AdminLayout")}, // Cause Infinite Loading
  loading: Loader,
});

const App = () => {
   const { app, api } = React.useContext(FirebaseContext);

   const menu = routes.map((route, index) => {
      return route.component ? (
         <Route
            key={index}
            path={route.path}
            exact={route.exact}
            name={route.name}
            render={(props) => <route.component {...props} />}
         />
      ) : null;
   });

   
  return (
    <Aux>
      <ScrollToTop>
        <Suspense fallback={<Loader />}>
          <Switch>
            {menu}
            <Route path="/" component={AdminLayout} />
          </Switch>
        </Suspense>
      </ScrollToTop>
    </Aux>
  );  
}

export default App;

I lost in the debugging process when I try to know what's going on inside this AdminLayout component. This component is coming from the template. ./App/layout/AdminLayout/index.js

import React, { Component, Suspense } from "react";
import { Route, Switch, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import Fullscreen from "react-full-screen";
import windowSize from "react-window-size";

import Navigation from "./Navigation";
import NavBar from "./NavBar";
import Breadcrumb from "./Breadcrumb";
import Configuration from "./Configuration";
import Loader from "../Loader";
import routes from "../../../routes";
import Aux from "../../../hoc/_Aux";
import * as actionTypes from "../../../store/actions";

//import '../../../app.scss';

class AdminLayout extends Component { 
  fullScreenExitHandler = () => {
    if (
      !document.fullscreenElement &&
      !document.webkitIsFullScreen &&
      !document.mozFullScreen &&
      !document.msFullscreenElement
    ) {
      this.props.onFullScreenExit();
    }
  };

  UNSAFE_componentWillMount() {
    if (
      this.props.windowWidth > 992 &&
      this.props.windowWidth <= 1024 &&
      this.props.layout !== "horizontal"
    ) {
      this.props.onUNSAFE_componentWillMount();
    }
  }

  mobileOutClickHandler() {    
    if (this.props.windowWidth < 992 && this.props.collapseMenu) {
      this.props.onUNSAFE_componentWillMount();
    }
  }

  render() {    
    /* full screen exit call */
    document.addEventListener("fullscreenchange", this.fullScreenExitHandler);
    document.addEventListener(
      "webkitfullscreenchange",
      this.fullScreenExitHandler
    );
    document.addEventListener(
      "mozfullscreenchange",
      this.fullScreenExitHandler
    );
    document.addEventListener("MSFullscreenChange", this.fullScreenExitHandler);

    const menu = routes.map((route, index) => {
      return route.component ? (
        <Route
          key={index}
          path={route.path}
          exact={route.exact}
          name={route.name}
          render={(props) => <route.component {...props} />}
        />
      ) : null;
    });

    let mainClass = ["pcoded-wrapper"];
    if (
      this.props.layout === "horizontal" &&
      this.props.subLayout === "horizontal-2"
    ) {
      mainClass = [...mainClass, "container"];
    }
    return (
      <Aux>
        <Fullscreen enabled={this.props.isFullScreen}>
          <Navigation />
          <NavBar />
          <div
            className="pcoded-main-container"
            onClick={() => this.mobileOutClickHandler}
          >
            <div className={mainClass.join(" ")}>
              <div className="pcoded-content">
                <div className="pcoded-inner-content">
                  <Breadcrumb />
                  <div className="main-body">
                    <div className="page-wrapper">
                      <Suspense fallback={<Loader />}>
                        <Switch>
                          {menu}
                          <Redirect from="/" to={this.props.defaultPath} />
                        </Switch>
                      </Suspense>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <Configuration />
        </Fullscreen>
      </Aux>
    );
  }
}

const mapStateToProps = (state) => {
  debugger
  return {
    defaultPath: state.defaultPath,
    isFullScreen: state.isFullScreen,
    collapseMenu: state.collapseMenu,
    layout: state.layout,
    subLayout: state.subLayout,
  };
};

const mapDispatchToProps = (dispatch) => {
  debugger
  return {
    onFullScreenExit: () => dispatch({ type: actionTypes.FULL_SCREEN_EXIT }),
    onUNSAFE_componentWillMount: () =>
      dispatch({ type: actionTypes.COLLAPSE_MENU }),
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(windowSize(AdminLayout));

Could anyone have an idea why this is happening or maybe how to debug to find the problem? Thank you.

EDIT: When I import the AdminLayout directly without using Loadable, it works fine. How to make this work using Loadable?

resant
  • 31
  • 2
  • If you have additional information to share, you should edit the question to include that. Don't leave a comment except to discuss directly with others. – Doug Stevenson Oct 15 '20 at 00:52

0 Answers0