Javascript <;开关>;组件匹配react-router-4中的空值
我正在尝试迁移到使用React Router 4,但在理解Javascript <;开关>;组件匹配react-router-4中的空值,javascript,reactjs,react-router,Javascript,Reactjs,React Router,我正在尝试迁移到使用React Router 4,但在理解组件的逻辑时遇到了一些问题,因为它在中用于处理404(或不匹配)路由 对于我的输入JavaScript文件,我设置了以下路径 index.js <Switch> <Route path="/login" component={Login} /> <Route path="/forgot-password" component={ForgotPassword} /> <Rou
组件的逻辑时遇到了一些问题,因为它在中用于处理404(或不匹配)路由
对于我的输入JavaScript文件,我设置了以下路径
index.js
<Switch>
<Route path="/login" component={Login} />
<Route path="/forgot-password" component={ForgotPassword} />
<Route path="/email-verification" component={EmailVerification} />
<Route component={App} />
</Switch>
<Switch>
<Route path="/dashboard" component={Dashboard} />
<Route path="/accounts" component={Account} />
<Authorize permissions={['view-admin']}>
<Route path="/admin" component={Admin} />
</Authorize>
<Route path="/users" component={Users} />
<Route component={NotFound} />
</Switch>
这就是我的问题所在。Authorize
组件根据传递的权限检查用户是否拥有这些权限,如果拥有这些权限,则直接呈现子项,如果没有,则从render()
返回null
这里的预期行为是,当权限不足且组件呈现时,
根本不呈现
根据报告:
渲染匹配的第一个子级。A.
没有路径总是匹配的
但是,如果我转到
组件之后声明的任何路由,则路由器将匹配到null
。这意味着,根据上面的示例,转到/users
返回null。react router的预期行为是否返回
组件中的第一个匹配项,即使它是null
值
我如何为这种情况提供一个“全面”的路由(404),而不为App.js中的许多经过身份验证的路由中的每一个创建
组件?null
值真的应该产生匹配吗?不幸的是,react router的交换机
组件不会与嵌套在其他组件中的路由一起工作,如您的示例中所示。如果你检查,它会说:
a的所有子级都应为或元素
。。。因此,您的授权
组件作为开关
的直接子组件实际上并不合法
如果你有一个通读,你会看到它相当邪恶地读取它每个孩子的道具,并在每个孩子的路径
(或from
)道具上手动应用react router的匹配路径
方法来确定应该渲染哪个道具
因此,在您的案例中发生的是Switch
迭代其子级,直到它到达您的Authorize
组件。然后它查看该组件的道具,既找不到路径
也找不到来自道具的,并在未定义的路径上调用匹配路径
。正如您自己所注意到的,“没有路径的a总是匹配的”,因此matchPath
返回true,并且Switch呈现Authorize
组件(忽略任何后续路由或重定向,因为它认为它找到了匹配)。但是,Authorize
组件中嵌套的“/admin”路由与当前路径不匹配,因此从渲染返回空结果
我在工作中也面临着类似的情况。我的计划是用一个自定义组件替换路由代码中react router的开关
,该组件迭代其子级,依次手动渲染每个子级,并返回第一个返回非null值的结果。我会在试一试后更新这个答案
编辑:好吧,那不行。我无法找到一种受支持的方法来手动调用子对象上的“render”。很抱歉,我无法为您提供一个解决切换限制的方法。与Robert所说的类似,下面是我的做法
class NullComponent extends React.Component {
shouldComponentBeRenderedByRoute() {
return false;
}
render() {
return null;
}
}
class CustomSwitch extends React.Component {
render() {
return (
// React.Children.map returns components even for null, which
const children = React.Children.toArray(this.props.children).map(child => {
const { render, shouldComponentBeRenderedByRoute } = child.type.prototype;
if (shouldComponentBeRenderedByRoute && !shouldComponentBeRenderedByRoute.call(child)) {
return null;
}
if (shouldComponentBeRenderedByRoute) {
return render.call(child);
}
return child;
});
return <Switch>{children}</Switch>;
);
}
}
类NullComponent扩展了React.Component{
应该由路由()指定的组件{
返回false;
}
render(){
返回null;
}
}
类CustomSwitch扩展了React.Component{
render(){
返回(
//React.Children.map即使为null也返回组件,这
const children=React.children.toArray(this.props.children).map(child=>{
const{render,shouldcomponentberendedbyroute}=child.type.prototype;
if(shouldcomponentberendedbyroute&!shouldcomponentberendedbyroute.call(子)){
返回null;
}
如果(应按路线指定组件){
返回render.call(子级);
}
返回儿童;
});
返回{children};
);
}
}
那就用它吧
<CustomSwitch>
<Route path... />
<NullComponent />
<Route path... />
</CustomSwitch>
在这里,没有shouldcomponentberedbyroute
功能的组件被假定为来自react router
的有效路由组件,但您可以添加更多条件(可能使用路径道具)来检查它是否是有效路由,以防任何人在>=2019年读到它,处理此行为的一种方法是简单地包装Route组件,如下所示:
import React from 'react'
import { Route } from 'react-router-dom'
type Props = {
permissions: string[]
componentWhenNotAuthorized?: React.ElementType
}
const AuthorizedRoute: React.FunctionComponent<Props> = ({
permissions,
componentWhenNotAuthorized: ComponentWhenNotAuthorized,
...rest
}) => {
const isAuthorized = someFancyAuthorizationLogic(permissions)
return isAuthorized
? <Route {...rest} />
: ComponentWhenNotAuthorized
? <ComponentWhenNotAuthorized {...rest} />
: null
}
export default AuthorizedRoute
从“React”导入React
从“react router dom”导入{Route}
类型道具={
权限:字符串[]
未授权时的组件:React.element类型
}
常量:React.FunctionComponent=({
权限,
未授权的组件:未授权的组件,
休息
}) => {
const isAuthorized=someFancyAuthorizationLogic(权限)
返回已授权
?
:未授权时的组件
?
:null
}
导出默认值
然后,简单地使用它:
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import AuthorizedRoute from 'some/path/AuthorizedRoute'
import Account from 'some/path/Account'
import Admin from 'some/path/Admin'
import Dashboard from 'some/path/Dashboard'
import NotFound from 'some/path/NotFound'
import Users from 'some/path/Users'
const AppRouter: React.FunctionComponent = () => (
<Switch>
<Route
component={Account}
path='/accounts'
/>
<AuthorizedRoute
component={Admin}
componentWhenNotAuthorized={NotFound}
path='/admin'
permissions={['view-admin']}
/>
<Route
component={Dashboard}
path='/dashboard'
/>
<Route
component={Users}
path='/users'
/>
<Route
component={NotFound}
/>
</Switch>
)
export default AppRouter
从“React”导入React
从“react router dom”导入{Route,Switch}
从“some/path/authorizedLote”导入authorizedLote
从“某些/路径/帐户”导入帐户
从“some/path/Admin”导入管理员
从“某些/路径/仪表板”导入仪表板
从“some/path/NotFound”导入NotFound
从“某些/路径/用户”导入用户
常量批准者:React.FunctionComponent=()=>(
)
导出默认批准程序
我也有同样的问题。你找到解决办法了吗?我相信问题是由我的部件造成的,但我从未发现为什么会出现这种情况。