高阶函数 - 元素类型无效:预期字符串或 class/function 但得到对象
Higher Order Function - Element Type is invalid: expected string or class/function but got object
我正在学习使用 Mobx、React 和 Auth 的教程 (https://www.johnstewart.dev/firebase-auth-react-mobx/)。但是我收到此错误消息
错误:元素类型无效:应为字符串(对于内置组件)或 class/function(对于复合组件)但得到:对象。检查 'Context.Consumer'.
的渲染方法
我怀疑这是由于以下代码造成的。这是一个高阶函数,它将组件包装在路由器中以测试身份验证状态。
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;
app.js 中的包装组件看起来像;
<Route path="/register" component={protectedRoute(Register)} />
我的理由是,当我手动将 authStore.loggedIn 更改为 true 时,一切都完美通过。但是,当我将 authStore.loggedIn 设置为 false 时,会出现错误。
毫无疑问,重定向非常简单,但搜索 Whosebug 并不是很有帮助,整个网络也不是。有什么建议吗??
register.js 请求的文件,尽管这通过受保护的路由正确呈现。所以我不认为这是问题所在。
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));
功能rpotectedRoute
return不同类型之间是否登录。
- 当
authStore.loggedIn
为真时,它 return 是一个 React 组件 ,它类似于 (props) => <jsx/>
- 当
auth.loggedIn
为假时,它 return 是一个 React 元素 ,它类似于 <jsx/>
所以在这种情况下你应该这样做
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;
如果你是 React 新手,我建议你阅读 React components, elements and instances
我正在学习使用 Mobx、React 和 Auth 的教程 (https://www.johnstewart.dev/firebase-auth-react-mobx/)。但是我收到此错误消息
错误:元素类型无效:应为字符串(对于内置组件)或 class/function(对于复合组件)但得到:对象。检查 'Context.Consumer'.
的渲染方法我怀疑这是由于以下代码造成的。这是一个高阶函数,它将组件包装在路由器中以测试身份验证状态。
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;
app.js 中的包装组件看起来像;
<Route path="/register" component={protectedRoute(Register)} />
我的理由是,当我手动将 authStore.loggedIn 更改为 true 时,一切都完美通过。但是,当我将 authStore.loggedIn 设置为 false 时,会出现错误。
毫无疑问,重定向非常简单,但搜索 Whosebug 并不是很有帮助,整个网络也不是。有什么建议吗??
register.js 请求的文件,尽管这通过受保护的路由正确呈现。所以我不认为这是问题所在。
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));
功能rpotectedRoute
return不同类型之间是否登录。
- 当
authStore.loggedIn
为真时,它 return 是一个 React 组件 ,它类似于(props) => <jsx/>
- 当
auth.loggedIn
为假时,它 return 是一个 React 元素 ,它类似于<jsx/>
所以在这种情况下你应该这样做
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;
如果你是 React 新手,我建议你阅读 React components, elements and instances