当我点击 locathost:3000/faq 或任何其他有效路由时,React 会在页面底部显示有效路由内容和 NotFound(基本上是 404 自定义页面)组件。我只想在命中无效路由时显示 NotFound 组件内容 例如:本地主机:3000/not-existing-url
const routes = [
{
path: '/',
component: HomePage,
is_private: false,
},
{
path: '/faq',
component: RedirectFaqToSupport,
is_private: false,
},
{
path: '/about-us',
component: About,
is_private: false,
},
{
path: '/contact-us',
component: Contact,
is_private: false,
},
{
component: NotFound,
is_private: false,
path: '*'
},
]
这是我的 App.js 组件代码。
class App extends Component {
constructor() {
super()
this.state = {
redirectToReferrer: false, // may not need this anymore
}
}
render() {
const { isMobile } = this.props
const renderLoader = () => (
<Columns.Column size={12}>
<div className="has-text-centered" style={{ marginTop: '15%' }}>
<i className="fas fa-3x fa-cog fa-spin"></i>
</div>
</Columns.Column>
)
return (
<Suspense fallback={renderLoader()}>
<BrowserRouter>
<Provider>
<ScrollToTop />
<Subscribe to={[AppContainer]}>
{(auth) => {
return (
<>
<Header
isAuth={auth.state.isAuth}
modalViewType={auth.state.modalViewType}
unreadMessageCount={auth.state.unreadMessageCount}
auth={auth}
/>
<ErrorBoundary>
<div className="page-master-container">
<Switch>
<BuildRoutes
isMobile={isMobile}
isAuth={auth.state.isAuth}
auth={auth}
/>
</Switch>
</div>
</ErrorBoundary>
<Footer isAuth={auth.state.isAuth} />
</>
)
}}
</Subscribe>
</Provider>
</BrowserRouter>
</Suspense>
)
}
}
这是BuidRoutes组件代码
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={(props) =>
rest.isAuth === true ? (
<Component {...props} {...rest} />
) : (
<Redirect
to={{
pathname: '/login',
state: { from: props.location },
}}
/>
)
}
/>
)
export const BuildRoutes = ({ isMobile, isAuth, auth }) => {
const location = useLocation()
useEffect(() => {
const queryParams = QueryString.parse(location.search)
setFeatureFlag(queryParams)
}, [location])
return (
<>
{routes.map(
({ path, component: Component, is_private, is_mother }, key) =>
!is_private ? (
<Route
exact={is_mother ? false : true}
path={path}
key={key}
render={(props) => (
<Component
{...props}
isMobile={isMobile}
isAuth={isAuth}
auth={auth}
/>
)}
/>
) : (
<PrivateRoute
isAuth={isAuth}
isMobile={isMobile}
auth={auth}
exact={is_mother ? false : true}
path={path}
key={key}
component={Component}
/>
)
)}
<Route
exact
path="/brand/:brandName"
render={(props) => {
const { brandName } = props.match.params
if (bikeBrands.includes(brandName)) {
return <Redirect to={`/brand/${brandName}-rental`} />
}
return <BrandLandingPage brandName={brandName} />
}}
/>
</>
)
}
注意:我也尝试了以下方法,但没有帮助。仍然显示 NotFound 组件以及有效的路由组件
export const BuildRoutes = ({ isMobile, isAuth, auth }) => {
const location = useLocation()
useEffect(() => {
const queryParams = QueryString.parse(location.search)
setFeatureFlag(queryParams)
}, [location])
return (
<>
{routes.map(
({ path, component: Component, is_private, is_mother }, key) =>
!is_private ? (
<Route
exact={is_mother ? false : true}
path={path}
key={key}
render={(props) => (
<Component
{...props}
isMobile={isMobile}
isAuth={isAuth}
auth={auth}
/>
)}
/>
) : (
<PrivateRoute
isAuth={isAuth}
isMobile={isMobile}
auth={auth}
exact={is_mother ? false : true}
path={path}
key={key}
component={Component}
/>
)
)}
<Route
component={NotFound}
/>
<Route
exact
path="/brand/:brandName"
render={(props) => {
const { brandName } = props.match.params
if (bikeBrands.includes(brandName)) {
return <Redirect to={`/brand/${brandName}-rental`} />
}
return <BrandLandingPage brandName={brandName} />
}}
/>
</>
)
}
我正在使用“react-router-dom”:“^5.2.0”,
Switch
组件渲染与位置匹配的第一个子 <Route>
或 <Redirect>
。不幸的是,这也导致了它遇到的第一个非Route
和非Redirect
子级的渲染,在本例中为BuildRoutes
。
<Switch>
<BuildRoutes // <-- first child/match and always rendered
isMobile={isMobile}
isAuth={auth.state.isAuth}
auth={auth}
/>
</Switch>
要记住的要点:
Switch
组件中渲染的所有路由都是排他性匹配和渲染的,例如“第一个匹配的孩子......”。BuildRoutes
组件正在渲染它渲染的路线,因为路线不是直接是Switch
组件的子级。这意味着在 NotFound
上渲染的 path="*"
组件将始终匹配并始终被渲染。
将
Switch
移入 BuildRoutes
,以便直接将路由渲染为子级,这样就可以应用 独占 路由匹配和渲染。
<ErrorBoundary>
<div className="page-master-container">
<BuildRoutes
isMobile={isMobile}
isAuth={auth.state.isAuth}
auth={auth}
/>
/div>
</ErrorBoundary>
const PrivateRoute = ({ isAuth, ...props }) => {
const from = useLocation();
return isAuth
? <Route {...props} />
: <Redirect to={{ pathname: '/login', state: { from } }} />;
};
export const BuildRoutes = ({ isMobile, isAuth, auth }) => {
const location = useLocation();
useEffect(() => {
const queryParams = QueryString.parse(location.search);
setFeatureFlag(queryParams);
}, [location]);
return (
<Switch>
{routes.map(({ path, component, is_private, is_mother }) => {
const ChildRoute = is_private ? PrivateRoute : Route;
const Component = component;
return (
<ChildRoute
key={path}
exact={!is_mother}
path={path}
render={(props) => (
<Component {...props} {...{ isMobile, isAuth, auth }} />
)}
/>
);
})}
<Route
exact
path="/brand/:brandName"
render={(props) => {
const { brandName } = props.match.params
if (bikeBrands.includes(brandName)) {
return <Redirect to={`/brand/${brandName}-rental`} />
}
return <BrandLandingPage brandName={brandName} />
}}
/>
</Switch>
);
};