React Router v4 Redirect not working

88,251

Solution 1

The asker posted an issue on GitHub, and got this apparently unpublished hidden guide (edit: now published) that helped me out too. I'm posting it here because I ran into the same problem and want others to avoid our pain.

The problem is that mobx-react and react-redux both supply their own shouldComponentUpdate() functions that only check for prop changes, but react-router sends state down through the context. When the location changes, it doesn't change any props, so it doesn't trigger an update.

The way around this is to pass the location down as a prop. The above guide lists several ways to do that, but the easiest is to just wrap the container with the withRouter() higher order component:

export default withRouter(observer(MyComponent))

or, for redux:

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

Solution 2

You should render only Redirect in your render method:

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

but here is my favorite solution without using the Redirect component

  1. import import { withRouter } from 'react-router-dom';
  2. export default withRouter(MyComponent);
  3. Finally, in your action method, assume that handlingButtonClick
handlingButtonClick = () => {
  this.props.history.push("/") //doing redirect here.
}

Solution 3

<Redirect /> should not be inside <Switch></Switch> tags.

Solution 4

Be careful when composing the Router with other components like translation providers, theme providers, etc .. After some time I found that your App has to be strictly wrapped by the Router, like this:

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

Hope this helps somebody

Solution 5

You're missing a / in front of intro

<Route exact path="/" render={()=>(
  Store.isFirstTime ? <Redirect to="/intro" /> : <Home state={Store} />         
)} />
Share:
88,251
mdanishs
Author by

mdanishs

Updated on August 29, 2021

Comments

  • mdanishs
    mdanishs over 2 years

    I have a route which redirects after checking a condition like this

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

    The url changes when the condition is true but the component is not mounted. The rest of the component code is as below.

    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>
        );
      }
    

    My App Component is contained with in the BrowserRouter like thi

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

    when I hit the url directly in the browser like 'localhost:3000/intro' component is mounted successfully, but when it goes through the redirect it doesn't display the component. How do I fix it?

    Edit

    So one detail was missing and I tried creating another project to reproduce the issue. My App component is a observer from mobx-react and it is exported as shown below

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

    I have created this repo with a sample code to reproduce the issue you can use it https://github.com/mdanishs/mobxtest/

    So when Components are wrapped into mobx-react observer the redirect is not working else it works fine

  • Tyler McGinnis
    Tyler McGinnis about 7 years
    Are you (or a lib you're using) using shouldComponentUpdate anywhere? github.com/ReactTraining/react-router/blob/v4/packages/…
  • Sisir
    Sisir about 7 years
    Wow, that was it. I was reading all kinds of doc from accepted answer but what I only needed is a / :)
  • dan-lee
    dan-lee almost 6 years
    Thank you very much, you helped me a lot! In my case IntlProvider was the culprit. I think it might be because of context or some shouldComponentUpdate magic.
  • LanfeaR
    LanfeaR over 5 years
    Great, this was the issue for me as well, had wrapped my routes in ThemeProvider which caused the issue.
  • Ryan Efendy
    Ryan Efendy over 5 years
    Yes generally React Router and Redux work fine together. Occasionally though, an app can have a component that doesn't update when the location changes (child routes or active nav links don't update). This is called Blocked Updates. The problem is that Redux implements shouldComponentUpdate and there's no indication that anything has changed if it isn't receiving props from the router. This is straightforward to fix. Find where you connect your component & wrap it in withRouter. github.com/ReactTraining/react-router/blob/master/packages/…
  • emandt
    emandt over 4 years
    It doesn't solves all cases. I've already tried both but it doesn't work. All works for the FIRST Redirect only, but if I return/redirect/history.push() at the first page and then try to do the SAME redirect as before, it seems refresh the DOM/page but I'm stucked there.
  • blah blah
    blah blah about 4 years
    this.props.history.push('/something') was the onlything that worked for me
  • Leo Gasparrini
    Leo Gasparrini almost 4 years
    me too, only works using withRouter and this.props.history.push thanks bro
  • Ash
    Ash almost 4 years
    Lol, of all the over-engineered solutions on this thread, this is the only that worked for me, and it's a one liner.
  • Hans Bouwmeester
    Hans Bouwmeester over 3 years
    Tried it. Didn't help in my case.
  • Casana
    Casana about 3 years
    This solved my problem! After placing <Redirect> out of the <Switch>, component renders correctly. Thanks!