I am working through a tutorial (https://www.johnstewart.dev/firebase-auth-react-mobx/) playing with Mobx, React and Auth. However I am getting this error message
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of 'Context.Consumer'.
which I suspect is due to the following code. This is meant as a higher order function that wraps the components within the router to test for authentication state.
import React from "react";
import authStore from "../../store/authStore";
import { Redirect } from "react-router-dom";
const protectedRoute = (RouteComponent) => {
if (authStore.loggedIn) {
return RouteComponent;
}
return <Redirect to="/login" />;
};
export default protectedRoute;
The wrapped component in app.js looks like;
<Route path="/register" component={protectedRoute(Register)} />
My reasoning is that when I manually change my authStore.loggedIn to true then it all passes perfectly. However when I set authStore.loggedIn to false the error appears.
No doubt it is something insanely simple with the Redirect but searching stackoverflow wasn't super helpful, nor was the web at large. Any suggestions??
register.js file as requested, though this renders correctly via the protected route. So I don't believe that this is where the issue lies.
import React, { useEffect, useState } from "react";
import { inject, observer } from "mobx-react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPlusSquare } from "@fortawesome/free-solid-svg-icons";
import BootstrapTable from "react-bootstrap-table-next";
import filterFactory, {
textFilter,
selectFilter,
} from "react-bootstrap-table2-filter";
import rp from "request-promise";
import Spinner from "../layout/Spinner";
const Register = (props) => {
const [dataLoaded, setdataLoaded] = useState(false);
useEffect(() => {
rp.get({
uri: "http://localhost:5050/api/risk",
json: true,
headers: {
"User-Agent": "Request-Promise",
},
})
.then((risks) => {
props.riskStore.riskList = risks;
console.log("Risks successfully loaded.");
setdataLoaded(true);
})
.catch((error) => {
console.log(error);
});
}, []);
const rowEvents = {
onClick: (e, row, rowIndex) => {
props.history.push(`/risk/${row._id}`);
},
};
return dataLoaded ? (
<div>
<br />
<h1 className="register-heading">Risk Register</h1>
<div className="row">
<div className="col-md-4">
<p className="register-text">
Please use the column headings to sort the register. To add a new
task, click the button to the right.
</p>
</div>
<div className="col-md-6"></div>
<div className="col-md-2">
<button
className="btn btn-primary"
onClick={() => props.history.push("/risk/new")}
>
<FontAwesomeIcon icon={faPlusSquare} /> New Task
</button>
</div>
</div>
<BootstrapTable
keyField="id"
data={props.riskStore.riskList}
columns={risksColumns}
filter={filterFactory()}
filterPosition="top"
striped={true}
hover={true}
condensed={true}
rowEvents={rowEvents}
bootstrap4={true}
/>
</div>
) : (
<Spinner />
);
};
const selectOptions = {
true: "Archived",
false: "Active",
};
const archiveFormatter = (cell, row, rowIndex, colIndex) => {
if (cell === true) {
return <span>Archived</span>;
} else {
return <span>Active</span>;
}
};
const risksColumns = [
{
dataField: "_id",
text: "",
hidden: true,
},
{
dataField: "riskName",
text: "Risk",
filter: textFilter(),
sort: true,
headerStyle: (column, colIndex) => {
return { width: "31%" };
},
},
{
dataField: "riskCategoryBroad.value",
text: "Broad Risk Category",
filter: textFilter(),
sort: true,
headerStyle: (column, colIndex) => {
return { textAlign: "center" };
},
align: "center",
},
{
dataField: "riskCategoryNarrow.value",
text: "Narrow Risk Category",
filter: textFilter(),
sort: true,
headerStyle: (column, colIndex) => {
return { textAlign: "center" };
},
align: "center",
},
{
dataField: "riskOfficerPrimary.value",
text: "Responsible Officer (Primary)",
filter: textFilter(),
sort: true,
headerStyle: (column, colIndex) => {
return { width: "20%", textAlign: "center" };
},
align: "center",
},
{
dataField: "grossRiskAssessment.grossRiskRating.label",
text: "Gross Risk Rating",
filter: textFilter(),
sort: true,
headerStyle: (column, colIndex) => {
return { textAlign: "center" };
},
align: "center",
},
{
dataField: "netRiskAssessment.netRiskRating.label",
text: "Net Risk Rating",
filter: textFilter(),
sort: true,
headerStyle: (column, colIndex) => {
return { textAlign: "center" };
},
align: "center",
},
{
dataField: "archived",
text: "Archived",
sort: true,
filter: selectFilter({ options: selectOptions }),
headerStyle: (column, colIndex) => {
return { textAlign: "center", width: "8%" };
},
formatter: archiveFormatter,
align: "center",
},
];
export default inject("riskStore")(observer(Register));
The function rpotectedRoute
return different types between wether you are login.
authStore.loggedIn
is true, it returns a React Component, it's something like (props) => <jsx/>
auth.loggedIn
is false, it returns a React Element, it's something like <jsx/>
So in this case you should do
import React from "react";
import authStore from "../../store/authStore";
import { Redirect } from "react-router-dom";
const protectedRoute = (RouteComponent) => {
if (authStore.loggedIn) {
return RouteComponent;
}
return () => <Redirect to="/login" />;
};
export default protectedRoute;
If you are new to react, I recommand you to read React components, elements and instances