React 路由器警告: <Route> 元素不应从受控变为不受控制(反之亦然)



我试图理解我在使用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="/"/>
}

它工作完美!!

最新更新