Using React Context to Integrate Firebase Cause Infinite Loading When Import Component using Loadable

282 views Asked by At

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?

0

There are 0 answers