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?