AnApprentice
AnApprentice

Reputation: 111080

With React-Router-4, how to programmatically set the index route `/`

With React-Router-4 how can I programmatically set the index route /

For example, if the user is not authenticated, this should trigger:

<Route path="/" component={LandingPage}>

If the user is authenticated:

<PrivateRoute path="/dashboard" component={Dashboard} />

For your information on PrivateRoute

Updated attempt

const WithMainLayout = ({component: Component, ...more}) => {
  return <Route {...more} render={props => {
    return (
      <MainLayout {...props}>
        <Component {...props} />
      </MainLayout>
    );
  }}/>;
};

const isLoggedIn = () => {
  console.log('do it')
  return true;
};


....

<WithMainLayout exact path="/" component={Home} render={() => (
  isLoggedIn() ? (
    <Redirect to="/dashboard" />
  ) : (
    <Home />
  )
)}/>

See above attempt, for some reason, the console.log is not outputting anything in the isLoggedIn func.

Upvotes: 1

Views: 934

Answers (3)

Shubham Khatri
Shubham Khatri

Reputation: 282040

So in your Updated Code the problem is that you return

<Route {...more} render={props => {

so what essentially happens is that the render prop passed on to the WithMainLayout component which is available with {...more} is overwritten by you custom prop and hence isLoggedIn is never called.

The solution is simple, you can just interchange the {...more} and render={props => {}} and also wrap your Home component with WithMainLayout so that it doesn't miss the Layout

You code will look like

const WithMainLayout = ({component: Component, ...more}) => {
  return <Route render={props => {
    return (
      <MainLayout {...props}>
        <Component {...props} />
      </MainLayout>
    );
  }}  {...more} />;
};

const isLoggedIn = () => {
  console.log('do it')
  return true;
};


....

<WithMainLayout exact path="/" component={Home} render={() => (
  isLoggedIn() ? (
    <Redirect to="/dashboard" />
  ) : (
    <WithMainLayout component={Home} />
  )
)}/>

Upvotes: 2

Nick Brady
Nick Brady

Reputation: 6592

You use the history prop. You can read about it here: https://reacttraining.com/react-router/web/api/history

Essentially you wrap your component in the withRouter HOC, and it will pass the history prop to your component which you'll see here: https://reacttraining.com/react-router/web/api/withRouter. It blends very well with React Recompose. I modified the "basic example" of the react router docs as an example here of using withRouter with the history prop

// create-react-app test && cd test && npm i && npm install react-router-dom
// replace contents of App.js then `npm run start`
import React, { Component } from 'react';
import { withRouter } from 'react-router'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

class BasicExample extends Component {
  render() {
    return(
      <Router>
        <div>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
          </ul>
          <hr/>
          <Route exact path="/" component={withRouter(Home)}/>
          <Route path="/about" component={About}/>
        </div>
      </Router>
    )
  }
}

class Home extends Component {
  render() {
    const {history} = this.props;
    const handleClick = (e) => {
      history.push("/about")
    }
    console.log(history)
    return (
      <div>
        <h2>Home</h2>
        <button onClick={handleClick}>To about</button>
      </div>
    )
  }
}

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

export default BasicExample;

If you're creating the link in your JSX, use the Link component, which looks like this

<Link to="/">...</Link>

If you're doing it inside of your PrivateRoute component, I think what you want is something more like the Redirect component: https://reacttraining.com/react-router/web/api/Redirect

  const PrivateRoute = ({ component: Component, ...rest }) => (
    <Route {...rest} render={props => (
      props.isAuthorized ? (
        <Component {...props}/>
      ) : (
        <Redirect to={{
          pathname: '/',
          state: { from: props.location }
        }}/>
      )
    )}/>)

Upvotes: 1

treyhakanson
treyhakanson

Reputation: 4931

I would put on onEnter method on the IndexRoute, and programmatically send the user to the correct location as needed:

<IndexRoute onEnter={handlePath}>

where the handler looks something like this, with userIsAutheticaed is replace by the appropriate code:

function handlePath(route, replace) {
   if (userIsAuthenticated) {
          replace('/dashboard');
   } else {
          replace('/');
   }
}

Upvotes: 1

Related Questions