反应路线问题与路线以外的标签
React Routes problem with Tags other than Route
使用"react-router-dom": "^5.3.2"
在我的组件中有以下代码:
render() {
return <div role="main">
<Switch>
<Route path="/auth" exact component={Auth} />
<PrivateRoute path="/" exact component={() => <>Main page</>} />
<IsGranted for={[ 'superuser' ]}>
<PrivateRoute path="/servers" exact component={ServerList} />
</IsGranted>
{/* or even nested in a <></> */}
<Route component={_ => <h1>Not found</h1>} />
</Switch>
</div>
}
const PrivateRoute = ({ component:Component, ...rest }) =>
<Route {...rest} render={props => isAuthenticated() ? <Component {...props}/> : <Redirect to={{ pathname:'/auth', state:{ from:props.location } }}/> }/>
const IfGranted = ({ children }) => condition() ? children : null
问题是,空标签 <>
下面的所有内容都会被忽略。
例如,如果我在 URL 中输入一些乱码,我希望呈现 Not found
。
只有当 <>...</>
被注释掉时才会发生这种情况。
这里有什么我可以做的吗?
Switch
组件的唯一有效子组件是 Route
组件(包括自定义路由组件)和 Redirect
组件。 React.Fragment
打破了这种抽象。 Switch
组件 returns 匹配位置 或 [=89= 的第一个子 <Route>
或 <Redirect>
] 在子组件两者都不是的情况下,that child 被返回并且它下面的任何东西都不可到达,即“Not Found”路由。
从我看到的您的代码片段来看,不需要 React.Fragment
包装 PrivateRoute
组件。
- 删除
"/servers"
路由周围的无关片段。
- 对 React 组件引用使用路由的
component
属性,对内联函数使用 render
属性。
- 按路由路径的特殊性以相反的顺序排列路由,这样就无需在每条路由上指定
exact
属性。由于您有一个“未找到”的捕获所有路由,因此其上方的主路径 "/"
将 需要 exact
属性以将其排除在所有其他通用匹配之外。
代码
render() {
return <div role="main">
<Switch>
<Route path="/auth" component={Auth} />
<PrivateRoute path="/servers" component={ServerList} />
<PrivateRoute exact path="/" render={() => <>Main page</>} />
<Route render={() => <h1>Not found</h1>} />
</Switch>
</div>
}
私有路由
为了使 PrivateRoute
与 Route
组件更加对齐 API 它应该采用与 Route
相同的道具并渲染 Route
或 Redirect
组件。使用 useLocation
挂钩访问当前 location
对象以进行重定向。
示例:
const PrivateRoute = props => {
const location = useLocation();
return isAuthenticated()
? <Route {...props} />
: (
<Redirect
to={{
pathname:'/auth',
state: { from: location }
}}
/>
);
};
更新
要添加使用角色来限制访问的能力,我会直接包装路由组件,或者创建一个高阶组件,或者抽象另一个 PrivateRolesRoute
组件。
使用包装器
<Switch>
<Route path="/auth" component={Auth} />
<PrivateRoute
path="/servers"
render={props => (
<IsGranted for={['superuser']}>
<ServerList {...props} />
</IsGranted>
)}
/>
<PrivateRoute exact path="/" render={() => <>Main page</>} />
<Route render={() => <h1>Not found</h1>} />
</Switch>
使用 HOC
创建一个 HOC,它接受一个要装饰的组件和一个角色数组,以及 returns 一个包装的组件。
const withIsGranted = (Component, roles = []) => props => (
<IsGranted for={roles}>
<Component {...props} />
</IsGranted>
);
装饰你想要角色保护的组件。
export default withIsGranted(ServerList, ['superuser']);
在路由中使用导出的装饰组件。它看起来与以前没有什么不同。
<Switch>
<Route path="/auth" component={Auth} />
<PrivateRoute path="/servers" component={ServerList} />
<PrivateRoute exact path="/" render={() => <>Main page</>} />
<Route render={() => <h1>Not found</h1>} />
</Switch>
使用PrivateRolesRoute
路由组件
创建一个新的私有路由组件,该组件采用额外的道具并处理受保护路由的条件渲染。
const PrivateRolesRoute = ({ roles = [], ...props }) => {
const location = useLocation();
return isAuthenticated()
? (
<IsGranted for={roles}>
<Route {...props} />
</IsGranted>
)
: (
<Redirect
to={{
pathname:'/auth',
state: { from: location }
}}
/>
);
};
使用新的 PrivateRoleRoute
并传递 roles
属性。
<Switch>
<Route path="/auth" component={Auth} />
<PrivateRoleRoute
path="/servers"
component={ServerList}
roles={['superuser']}
/>
<PrivateRoute exact path="/" render={() => <>Main page</>} />
<Route render={() => <h1>Not found</h1>} />
</Switch>
使用"react-router-dom": "^5.3.2"
在我的组件中有以下代码:
render() {
return <div role="main">
<Switch>
<Route path="/auth" exact component={Auth} />
<PrivateRoute path="/" exact component={() => <>Main page</>} />
<IsGranted for={[ 'superuser' ]}>
<PrivateRoute path="/servers" exact component={ServerList} />
</IsGranted>
{/* or even nested in a <></> */}
<Route component={_ => <h1>Not found</h1>} />
</Switch>
</div>
}
const PrivateRoute = ({ component:Component, ...rest }) =>
<Route {...rest} render={props => isAuthenticated() ? <Component {...props}/> : <Redirect to={{ pathname:'/auth', state:{ from:props.location } }}/> }/>
const IfGranted = ({ children }) => condition() ? children : null
问题是,空标签 <>
下面的所有内容都会被忽略。
例如,如果我在 URL 中输入一些乱码,我希望呈现 Not found
。
只有当 <>...</>
被注释掉时才会发生这种情况。
这里有什么我可以做的吗?
Switch
组件的唯一有效子组件是 Route
组件(包括自定义路由组件)和 Redirect
组件。 React.Fragment
打破了这种抽象。 Switch
组件 returns 匹配位置 或 [=89= 的第一个子 <Route>
或 <Redirect>
] 在子组件两者都不是的情况下,that child 被返回并且它下面的任何东西都不可到达,即“Not Found”路由。
从我看到的您的代码片段来看,不需要 React.Fragment
包装 PrivateRoute
组件。
- 删除
"/servers"
路由周围的无关片段。 - 对 React 组件引用使用路由的
component
属性,对内联函数使用render
属性。 - 按路由路径的特殊性以相反的顺序排列路由,这样就无需在每条路由上指定
exact
属性。由于您有一个“未找到”的捕获所有路由,因此其上方的主路径"/"
将 需要exact
属性以将其排除在所有其他通用匹配之外。
代码
render() {
return <div role="main">
<Switch>
<Route path="/auth" component={Auth} />
<PrivateRoute path="/servers" component={ServerList} />
<PrivateRoute exact path="/" render={() => <>Main page</>} />
<Route render={() => <h1>Not found</h1>} />
</Switch>
</div>
}
私有路由
为了使 PrivateRoute
与 Route
组件更加对齐 API 它应该采用与 Route
相同的道具并渲染 Route
或 Redirect
组件。使用 useLocation
挂钩访问当前 location
对象以进行重定向。
示例:
const PrivateRoute = props => {
const location = useLocation();
return isAuthenticated()
? <Route {...props} />
: (
<Redirect
to={{
pathname:'/auth',
state: { from: location }
}}
/>
);
};
更新
要添加使用角色来限制访问的能力,我会直接包装路由组件,或者创建一个高阶组件,或者抽象另一个 PrivateRolesRoute
组件。
使用包装器
<Switch> <Route path="/auth" component={Auth} /> <PrivateRoute path="/servers" render={props => ( <IsGranted for={['superuser']}> <ServerList {...props} /> </IsGranted> )} /> <PrivateRoute exact path="/" render={() => <>Main page</>} /> <Route render={() => <h1>Not found</h1>} /> </Switch>
使用 HOC
创建一个 HOC,它接受一个要装饰的组件和一个角色数组,以及 returns 一个包装的组件。
const withIsGranted = (Component, roles = []) => props => ( <IsGranted for={roles}> <Component {...props} /> </IsGranted> );
装饰你想要角色保护的组件。
export default withIsGranted(ServerList, ['superuser']);
在路由中使用导出的装饰组件。它看起来与以前没有什么不同。
<Switch> <Route path="/auth" component={Auth} /> <PrivateRoute path="/servers" component={ServerList} /> <PrivateRoute exact path="/" render={() => <>Main page</>} /> <Route render={() => <h1>Not found</h1>} /> </Switch>
使用
PrivateRolesRoute
路由组件创建一个新的私有路由组件,该组件采用额外的道具并处理受保护路由的条件渲染。
const PrivateRolesRoute = ({ roles = [], ...props }) => { const location = useLocation(); return isAuthenticated() ? ( <IsGranted for={roles}> <Route {...props} /> </IsGranted> ) : ( <Redirect to={{ pathname:'/auth', state: { from: location } }} /> ); };
使用新的
PrivateRoleRoute
并传递roles
属性。<Switch> <Route path="/auth" component={Auth} /> <PrivateRoleRoute path="/servers" component={ServerList} roles={['superuser']} /> <PrivateRoute exact path="/" render={() => <>Main page</>} /> <Route render={() => <h1>Not found</h1>} /> </Switch>