React Router 警告: <Route> 元素不应从受控更改为不受控(反之亦然)

Kir*_*ran 10 reactjs react-router

我试图了解在使用 React Router 时看到的特定警告背后的细微差别。我试图根据用户是否登录来设置条件路由。我的代码如下:

\n
// AppRoutes.js\nexport\xc2\xa0const\xc2\xa0AppRoutes\xc2\xa0=\xc2\xa0({\xc2\xa0machine\xc2\xa0})\xc2\xa0=>\xc2\xa0{\n\xc2\xa0\xc2\xa0const\xc2\xa0[state]\xc2\xa0=\xc2\xa0useMachine(machine);\n  \n  let\xc2\xa0routes;\n  \n\xc2\xa0\xc2\xa0if\xc2\xa0(state.matches(\'authenticated\'))\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0routes\xc2\xa0=\xc2\xa0(\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<React.Fragment>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Route\xc2\xa0exact\xc2\xa0path="/"><HomePage\xc2\xa0/></Route>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Route\xc2\xa0path="/contacts"><ContactsList\xc2\xa0/></Route>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</React.Fragment>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0);\n\xc2\xa0\xc2\xa0}\xc2\xa0else\xc2\xa0if\xc2\xa0(state.matches(\'unauthenticated\'))\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0routes\xc2\xa0=\xc2\xa0(\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Route\xc2\xa0path="/">\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<LoginPage\xc2\xa0service={state.children.loginMachine}\xc2\xa0/>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</Route>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0);\n\xc2\xa0\xc2\xa0}\xc2\xa0else\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0routes\xc2\xa0=\xc2\xa0null;\n\xc2\xa0\xc2\xa0}\n  \n\xc2\xa0\xc2\xa0return\xc2\xa0(\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<BrowserRouter>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Switch>{routes}</Switch>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</BrowserRouter>\n\xc2\xa0\xc2\xa0);\n};\n
Run Code Online (Sandbox Code Playgroud)\n

在内部,HomePage 组件重定向到/contacts

\n
// HomePage.js\nexport const HomePage = () => {\n  return <Redirect to="/contacts" />;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

现在,使用此代码,应用程序可以按照我的需要运行,但我在控制台中记录了一条警告:

\n
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.\n
Run Code Online (Sandbox Code Playgroud)\n

我做了一些研究,我唯一能找到的是这个/sf/answers/3677845041/,这似乎表明有条件地渲染路由导致了问题。然而,路由的条件渲染才是重点——我不希望未经身份验证的用户访问/contacts

\n

经过一番尝试后,我将源代码修改如下:

\n
// AppRoutes.js\nexport\xc2\xa0const\xc2\xa0AppRoutes\xc2\xa0=\xc2\xa0({\xc2\xa0machine\xc2\xa0})\xc2\xa0=>\xc2\xa0{\n\xc2\xa0\xc2\xa0const\xc2\xa0[state]\xc2\xa0=\xc2\xa0useMachine(machine);\n  \n\xc2\xa0\xc2\xa0let\xc2\xa0routes;\n  \n\xc2\xa0\xc2\xa0if\xc2\xa0(state.matches(\'authenticated\'))\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0routes\xc2\xa0=\xc2\xa0(\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<React.Fragment>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Route\xc2\xa0path="/home">\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<HomePage\xc2\xa0/>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</Route>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Route\xc2\xa0path="/contacts">\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<ContactsList\xc2\xa0/>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</Route>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Redirect\xc2\xa0to="/home"\xc2\xa0/>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</React.Fragment>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0);\n\xc2\xa0\xc2\xa0}\xc2\xa0else\xc2\xa0if\xc2\xa0(state.matches(\'unauthenticated\'))\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0routes\xc2\xa0=\xc2\xa0(\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<React.Fragment>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Route\xc2\xa0path="/login">\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<LoginPage\xc2\xa0service={state.children.loginMachine}\xc2\xa0/>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</Route>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Redirect\xc2\xa0to="/login"\xc2\xa0/>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</React.Fragment>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0);\n\xc2\xa0\xc2\xa0}\n  \n\xc2\xa0\xc2\xa0return\xc2\xa0(\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<BrowserRouter>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0<Switch>{routes}</Switch>\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0</BrowserRouter>\n\xc2\xa0\xc2\xa0);\n};\n\n// HomePage.js\nexport const HomePage = () => {\n  return <Redirect to="/contacts" />;\n};\n\n
Run Code Online (Sandbox Code Playgroud)\n

现在,此代码将经过身份验证的用户重定向到/contacts,并将未经身份验证的用户重定向到/login,并且不记录任何警告。

\n

一切都很好,但我仍然不明白为什么警告不再出现,这与我之前所做的有什么不同。据我所见和理解,我正在两个版本的代码中对路线进行条件渲染。为什么一个会记录警告,而另一个则不会?

\n

有什么指导吗??

\n

谢谢!

\n

Fil*_*váč 13

根据文档: https: //reactrouter.com/web/api/Switch/children-node

a 的所有子元素都<Switch>应该是<Route>or<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>
Run Code Online (Sandbox Code Playgroud)

解决方案 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>
Run Code Online (Sandbox Code Playgroud)

您还可以像这样格式化它:

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>
);
Run Code Online (Sandbox Code Playgroud)


小智 1

我正在处理类似的事情。我有这个:

<Switch>
  {aCondition && (
    <>
      <Route ... />
      <Route ... />
    </>
  )}
Run Code Online (Sandbox Code Playgroud)

这给我带来了同样的警告。看到你的代码,我发现你也有一个片段,而在“其他”中你没有。所以我尝试了:

{aCondition ? (
  <> 
    <Route ... />
    <Route ... />
  </>
) : (
  <></>
)}
Run Code Online (Sandbox Code Playgroud)

而且效果很好。似乎条件片段会混淆开关。