React Router v4重定向无法正常工作

41
我有一条路由,检查条件后会重定向,就像这样:

我有一条路由,检查条件后会重定向,就像这样

<Route exact path="/" render={()=>(
Store.isFirstTime ? <Redirect to="intro" /> : <Home state={Store}/>)}/>

当条件为真但组件未安装时,URL会发生更改。其余组件代码如下所示。

render() {
    return (
      <div>
        ...
        <Route exact path="/" render={()=>(
          Store.isFirstTime ? <Redirect to="intro" /> : <Home state={Store} />         
        )} />
        <Route path="/intro" render={()=>(<IntroWizard state={Store.userInfo}/>)} />
        <Route path="/home" render={()=>(<Home state={Store}/>)} />
        <Route render={()=>(<h1>404 Not Found</h1>)} />
        <Footer />
      </div>
    );
  }

我的App组件包含在BrowserRouter中,像这样

ReactDOM.render(<BrowserRouter>
    <App/>
</BrowserRouter>,
  document.getElementById('root')
);

当我直接在浏览器中输入'localhost:3000/intro'时,组件能够成功挂载,但是当通过重定向进入时,组件无法显示。我该如何解决?

编辑

所以还有一个细节缺失,并且我尝试创建另一个项目以复现该问题。我的App组件是mobx-react的观察者,并按如下方式导出。

let App = observer(class App { ... })
export default App

我已创建此存储库,其中包含一个示例代码以重现此问题,您可以使用它https://github.com/mdanishs/mobxtest/

当组件被包裹在mobx-react观察者中时,重定向无法正常工作,否则它将正常工作。


你在控制台中看到任何错误吗? - Tharaka Wijebandara
@TharakaWijebandara 控制台没有错误,事实上我刚刚尝试使用链接,它也不起作用。不知道出了什么问题。 - mdanishs
9个回答

53

提问者在GitHub上发布了一个问题,并获得了这篇明显未发布的隐藏指南(编辑:现在已经发布),这也帮助了我。我在这里发布它,因为我遇到了同样的问题,希望其他人能够避免我们的痛苦。

问题在于mobx-react和react-redux都提供了自己的shouldComponentUpdate()函数,仅检查属性更改,但是react-router通过上下文向下发送状态。当位置发生变化时,它不会更改任何属性,因此它不会触发更新。

解决方法是将位置作为属性向下传递。上面的指南列出了几种方法来做到这一点,但最简单的方法是使用withRouter()高阶组件包装容器:

export default withRouter(observer(MyComponent))

或者,对于Redux:

export default withRouter(connect(mapStateToProps)(MyComponent))

通常情况下,React Router 和 Redux 可以很好地配合使用。但是有时候,应用程序可能会出现组件在位置更改时不更新的情况(子路由或活动导航链接不更新)。这被称为阻塞更新。问题在于 Redux 实现了 shouldComponentUpdate,如果它没有从路由器接收到 props,则没有任何指示表明已更改任何内容。这很容易解决。找到连接组件的位置并将其包装在 withRouter 中即可。https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/redux.md#blocked-updates - Ryan Efendy

26

您的渲染方法中应仅呈现 Redirect

render() {
  return (<Redirect to="/" />);
}

但是这里是我最喜欢的解决方案,而不使用Redirect组件

  1. 导入import { withRouter } from 'react-router-dom';
  2. export default withRouter(MyComponent);
  3. 最后,在您的操作方法中,假设handlingButtonClick
handlingButtonClick = () => {
  this.props.history.push("/") //doing redirect here.
}

1
它并不能解决所有情况。我已经尝试了两种方法,但都不起作用。所有的操作仅适用于第一个重定向,但如果我在第一页返回/重定向/history.push(),然后尝试做与之前相同的重定向,它似乎会刷新DOM/页面,但我卡在那里了。 - emandt
1
this.props.history.push('/something') 是唯一对我有效的东西。 - blah blah
我也是,只有使用withRouter和this.props.history.push才能正常工作。 谢谢兄弟。 - Leo Gasparrini

21

<Redirect />不应该放在<Switch></Switch>标签内。


8
这个帖子中有很多过于复杂的解决方案,但唯独这一个对我有效,而且只需要一行代码就可以了。 - Ash
尝试过了,对我的情况没有帮助。 - Hans Bouwmeester
这解决了我的问题!在将<Redirect>放到<Switch>之外后,组件正确渲染。谢谢! - Casana

6

在与其他组件如翻译提供者、主题提供者等一起组合时,需要小心路由器的组合方式。经过一段时间的使用我发现,你的应用程序必须严格使用路由器进行包装,像这样:

<Provider store={store}>
  <ThemeProvider theme={theme}>
    <TranslationProvider
      namespaces={['Common', 'Rental']}
      translations={translations}
      defaultNS={'Common'}
    >
      <Router>
        <App />
      </Router>
    </TranslationProvider>
  </ThemeProvider>
</Provider>

希望这对某些人有所帮助。

非常感谢,你帮了我很多!在我的情况下,IntlProvider 是罪魁祸首。我认为这可能是由于上下文或某些 shouldComponentUpdate 魔法引起的。 - dan-lee
太好了,这也是我的问题,我将我的路由包装在 ThemeProvider 中导致了这个问题。 - LanfeaR

3

你漏掉了intro前面的 / 符号。

<Route exact path="/" render={()=>(
  Store.isFirstTime ? <Redirect to="/intro" /> : <Home state={Store} />         
)} />

你(或者你正在使用的库)是否在任何地方使用 shouldComponentUpdate?https://github.com/ReactTraining/react-router/blob/v4/packages/react-router/docs/guides/blocked-updates.md - Tyler McGinnis
2
哇,就是这样。我读了各种来自被接受答案的文档,但我只需要一个 / :) - Sisir

2
你可以尝试这样做:
第一步:在组件中导入“withRouter”如下所示:
import { withRouter } from "react-router-dom";

然后在您的组件末尾像这样导出组件:
export default withRouter(VerifyCode);

然后您可以将此代码添加到您的函数中:

 verify(e) {
    // after sever get 200
    this.props.history.push('/me/');
}

祝你好运


2
在重定向时添加 "exact"。
例如:
<Switch>
   <Route exact path="/">
      <Redirect to="/home" />
   </Route>
<Switch>

0
  const App = ({history}) =>{

  return history.push('/location')  }

0

我花了3个小时研究ReactJS重定向,这里是最好的重定向方法,我创建了一个像这样的模块:

import { useHistory, withRouter } from "react-router-dom";

const Redirect = (props: any) => { 
    const to = (props.to || '/');
    let history = useHistory();
        history.push(to);
        window.location.reload();
    return (
      <>
      </>
     )
   }
export default withRouter(Redirect);

它运行得非常完美! 您可以在其他文件中使用它! 像这样:

    export default function RedirectExample() {
      return (
        <Router>
          <Switch>
            <Route path="/page/2">
              <QueryPage />
            </Route>
            <Route path="/page">
              <MyRedirect to="/" />
            </Route>
          </Switch>
        </Router>
      );
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接