Javascript <;开关>;组件匹配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

我正在尝试迁移到使用React Router 4,但在理解
组件的逻辑时遇到了一些问题,因为它在中用于处理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=()=>(
)
导出默认批准程序

我也有同样的问题。你找到解决办法了吗?我相信问题是由我的部件造成的,但我从未发现为什么会出现这种情况。