Tom Bom
Tom Bom

Reputation: 1721

How to set correctly React routes?

I'm building an app with React and I'm using React routes.

I have 3 main routes:

index.js

ReactDOM.render(
    <Provider store={store}>
        <BrowserRouter>
            <Suspense fallback={<div>Loading...</div>}>
                <div>
                    <Switch>
                        <Route path="/" component={App} />
                        <Route path="/login" component={Login} />
                        <Route path="/forgotPassword" component={ForgotPassword} />
                    </Switch>
                </div>
            </Suspense>
        </BrowserRouter>
    </Provider>,
  document.getElementById('root')
);

App.js

{this.props.location.pathname === "/" && <Dashboard />}
<Route exact path="/users" component={Users} />
<Route path="/users/:id" component={UserPage} />
{!authenticated && <Redirect to="/login" />}

When I try to open "/", it redirects to "/login" but it doesn't render Login component.
When I replace {!authenticated && <Redirect to="/login" />} with {!authenticated && <Login>} it renders the component properly, but it doesn't change the url and it won't show the ForgotPassword page.

How do I set this properly?

Upvotes: 3

Views: 125

Answers (3)

Yousaf
Yousaf

Reputation: 29344

Problem is order of the Route components and the use of Switch component.

When you redirect to /login, Switch will render the first matching route; for the /login route, / route also matches.

This is why Login component isn't rendered. App component is rendered for both / and /login routes.

Solution

Couple of solutions to this problem are described below:

exact prop

One way to solve the problem is to use the exact prop. This will ensure that / route doesn't matches /login BUT it will cause another problem: nested routes inside App component won't be rendered. This is because for nested route to be rendered, parent route also needs to be rendered.

Re-order the Route components

Another solution is to change the order of your routes as:

<Switch>
   <Route path="/login" component={Login} />
   <Route path="/forgotPassword" component={ForgotPassword} />
   <Route path="/" component={App} />
</Switch>
                        

Upvotes: 1

Youness
Youness

Reputation: 1

You have to use render prop instead of component and the render prop give you the ability to do some checks and return the appropriate component

<Route render={(props) => !isAuth ? <Redirect to='/signin' /> : <Component {...props} /> } />

Upvotes: 0

AKX
AKX

Reputation: 169388

You'll need to reorder your switch:

<Switch>
    <Route path="/login" component={Login} />
    <Route path="/forgotPassword" component={ForgotPassword} />
    <Route path="/" component={App} />
</Switch>

Then, maybe make that App something like

{!authenticated ? <Redirect to="/login" /> : (
  <Switch>
    <Route path="/users/:id" component={UserPage} />
    <Route exact path="/users" component={Users} />
    <Route path="/" component={Dashboard />
  </Switch>
)}

(though it could be simpler to just keep all routes in the top-level router/switch)

Upvotes: 1

Related Questions