简体   繁体   中英

React Router v4 - Switch doesn't work with route render

I'm using React Router to display the same component but with different props on each route:

<BrowserRouter>
  <div>
    <Route exact path="/" render={() => LOGGED_IN ? <Redirect to="/profile" /> : <Login />} />
    <Route path="/profile/:id" render={(props) => <App {...props} page="profile" pageLadder={['Home', 'Profile']} />}/>
    <Route path="/team" render={() => <App page="team" pageLadder={['Home', 'Team']} />}/>
    <Route path="/transactions" render={() => <App page="transactions" pageLadder={['Home', 'Transactions']} />}/>
    <Route path="/tournaments" render={() => <App page="tournaments" pageLadder={['Home', 'Tournaments']} />}/>
    <Route path="/tournament/:id" render={(props) => <App {...props} page="tournament" pageLadder={['Home', 'Tournament', props.match.params.id]} />}/>
    <Route path="/match/:id" render={(props) => <App {...props} page="match" pageLadder={['Home', 'Match', props.match.params.id]} />} />
    <Route path="/scrims" render={() => <App page="scrims" pageLadder={['Home', 'Scrims']} />} />
    <Route path="/faq" render={() => <App page="faq" pageLadder={['Home', 'FAQ']} />} />
    <Route path="/staff" render={() => <App page="staff" pageLadder={['Home', 'Staff']} />} />
    <Route path="/privacy" render={() => <App page="privacy" pageLadder={['Home', 'Privacy Policy']} />} />
    <Route path="/tos" render={() => <App page="tos" pageLadder={['Home', 'Terms of Service']} />} />
  </div>
</BrowserRouter>

I also need to catch 404 errors, so I added Switch and <Route component={NotFound} /> :

<BrowserRouter>
  <Switch>
    <Route exact path="/" render={() => LOGGED_IN ? <Redirect to="/profile" /> : <Login />} />
    ... more routes
    <Route component={NotFound} />
  </Switch>
</BrowserRouter>

The 404 does work, but every <Link> element kind of stops working - after clicked, the url does change but the component stays the same, unless I refresh the site.

I tried changing my code to this to test:

<BrowserRouter>
  <Switch>
    <Route path="/team" component={Login} />
    <Route path="/profile/" component={App} />
  </Switch>
</BrowserRouter>

With this code the <Link> component does work as intended.

What can I do to make my first code work as intended?

From your code example:

class App extends Component {
  constructor(props){
    super(props);

    // appStore is an instance of react-easy-state library
    // App component puts the components together, the actual pages are in AppMain component (look below for code)
    appStore.changePage(this.props.page, this.props.pageLadder, this.props.match ? this.props.match.params.id : -1);
    // this function changes appStore.page.name value and it's a global type store
  }

  render() {
    return (
      <div>
        <div>
          <Sidebar />
          <AppMain />
        </div>
      </div>
    );
  }
}

You are calling appStore.changePage in the constructor , which only get's called one time, when the component is first initialized. Even though you have the component on several routes, it's not getting unmounted when you change the route and props, meaning that the constructor is never getting called again.

What you need to do is use componentDidUpdate to change the page when your props change:

componentDidUpdate (prevProps, prevState) {
  if(prevProps.page !== this.props.page) {
    appStore.changePage(this.props.page, this.props.pageLadder, this.props.match ? this.props.match.params.id : -1);
  }
}

Now, you compare the prevProps from the current props and if the page prop has changed, you need to trigger appStore.changePage again. Now, I'm not sure what appStore.changePage is doing so I'm not sure if you'll need to update <AppMain /> as well, but this should get you on the right track.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM