我试图理解我在使用React Router时看到的特定警告背后的细微差别。我试图根据用户是否登录来设置条件路由。我的代码如下:
// AppRoutes.js
export const AppRoutes = ({ machine }) => {
const [state] = useMachine(machine);
let routes;
if (state.matches('authenticated')) {
routes = (
<React.Fragment>
<Route exact path="/"><HomePage /></Route>
<Route path="/contacts"><ContactsList /></Route>
</React.Fragment>
);
} else if (state.matches('unauthenticated')) {
routes = (
<Route path="/">
<LoginPage service={state.children.loginMachine} />
</Route>
);
} else {
routes = null;
}
return (
<BrowserRouter>
<Switch>{routes}</Switch>
</BrowserRouter>
);
};
内部,主页组件重定向到/contacts
// HomePage.js
export const HomePage = () => {
return <Redirect to="/contacts" />;
};
现在有了这段代码,应用程序可以按我需要的方式工作了,但是我在控制台中得到了一个警告:
Warning: <Route> elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.
我做了一些研究,我唯一能找到的是这个https://stackoverflow.com/a/52540643,这似乎表明有条件地渲染路由导致了这个问题。然而,路由的条件呈现才是关键所在——我不希望未经身份验证的用户访问/contacts
然后经过一些尝试,我修改了源代码如下:
// AppRoutes.js
export const AppRoutes = ({ machine }) => {
const [state] = useMachine(machine);
let routes;
if (state.matches('authenticated')) {
routes = (
<React.Fragment>
<Route path="/home">
<HomePage />
</Route>
<Route path="/contacts">
<ContactsList />
</Route>
<Redirect to="/home" />
</React.Fragment>
);
} else if (state.matches('unauthenticated')) {
routes = (
<React.Fragment>
<Route path="/login">
<LoginPage service={state.children.loginMachine} />
</Route>
<Redirect to="/login" />
</React.Fragment>
);
}
return (
<BrowserRouter>
<Switch>{routes}</Switch>
</BrowserRouter>
);
};
// HomePage.js
export const HomePage = () => {
return <Redirect to="/contacts" />;
};
现在这段代码将认证的用户重定向到/contacts
,将未认证的用户重定向到/login
,并且不记录任何警告。
一切都很好,除了我仍然不明白为什么警告不再出现,这与我之前所做的有什么不同。就我所能看到和理解的,我在两个版本的代码中都做了有条件的路由渲染。为什么一个记录了警告,而另一个没有?
指导吗? ?
谢谢!
根据docs: https://reactrouter.com/web/api/Switch/children-node
<Switch>
的所有子元素都应该是<Route>
或<Redirect>
元素。
这意味着在<React.Fragment></React.Fragment>
或<></>
中包装路由不会削减它。
存在警告,因为这些不是<Route>
或<Redirect>
元素。
解决方案1:在<Route>
中换行,然后在<Switch>
中换行
我不喜欢这个解决方案,因为你必须重复回退路由
<Switch>
<Route exact path='/' component={Main} />
{some_condition && (
<Route path='/common'>
<Switch>
<Route exact path='/common/1' component={Secondary} />
<Route exact path='/common/2' component={Ternary} />
<Route component={NotFound} /> {/* this needs to be repeated here */}
</Switch>
</Route>
)}
<Route component={NotFound} />
</Switch>
解决方案2:将路由呈现为数组
最后这就是我想要的。你必须包含键,这很烦人,但不需要额外的元素。
<Switch>
<Route exact path='/' component={Main} />
{some_condition && [
<Route exact path='/common/1' key='/common/1' component={Secondary} />,
<Route exact path='/common/2' key='/common/2' component={Ternary} />
]}
<Route component={NotFound} />
</Switch>
你也可以这样格式化:
let routes;
if (some_condition) {
routes = [
<Route exact path='/common/1' key='/common/1' component={Secondary} />,
<Route exact path='/common/2' key='/common/2' component={Ternary} />
];
}
return (
<Switch>
<Route exact path='/' component={Main} />
{routes}
<Route component={NotFound} />
</Switch>
);
我正在处理类似的事情。我有这个:
<Switch>
{aCondition && (
<>
<Route ... />
<Route ... />
</>
)}
给我带来了同样的警告。看到你的代码,我发现你也有一个片段在&;else&;你还没有。所以我尝试了:
{aCondition ? (
<>
<Route ... />
<Route ... />
</>
) : (
<></>
)}
,它工作得很好。有条件片段似乎会混淆切换。
我刚刚遇到了同样的问题,Emanuel的回答并没有为我解决。什么工作是简单地使用<Switch>
代替<>
(或<React.Fragment>
)在另一个路由。
如果我错了请纠正我,但我认为使用react-router-dom嵌套路由/交换机是可以的。
的例子:
<Switch>
<Route exact path='/' component={Main} />
{some_condition && (
<Route path='/common'>
<Switch>
<Route exact path='/common/path' component={Secondary} />
</Switch>
</Route>
)}
<Route path='/settings' component={Settings} />
</Switch>
然而,这种方法需要一个公共路由路径("/common">
试试这个…
所有的选择对我都不起作用。所以我用了这个,它工作得很好:
首先我把所有的路由设置在一个数组中:
const routes = [
<Route ...>,
<Route ...>,
<Route ...>
]
然后执行map函数:
{
condition === true
? routes.map(myRoute => myRoute)
: <Redirect to="/"/>
}
它工作完美!!