Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass custom data to PrivateRoute component in React

I am new in ReactJS and starting my first app with React. I've been watching videos and going through various tutorials and finally managed to scaffold my first ReactRedux app with Login.

I've used AuthWorkflow example of ReactTraining website. There they used a PrivateRoute component to secure protected routes. I've implemented it and its working.

Problem:
Now I can't send any custom data or like user data to protected route. How can I sent it?

Code

import React from "react";
import {
  BrowserRouter as Router,
  Route,
  Link,
  Redirect,
  withRouter
} from "react-router-dom";

////////////////////////////////////////////////////////////
// 1. Click the public page
// 2. Click the protected page
// 3. Log in
// 4. Click the back button, note the URL each time

const AuthExample = () => (
  <Router>
    <div>
      <AuthButton />
      <ul>
        <li>
          <Link to="/public">Public Page</Link>
        </li>
        <li>
          <Link to="/protected">Protected Page</Link>
        </li>
      </ul>
      <Route path="/public" component={Public} />
      <Route path="/login" component={Login} />

       // Here I want to pass the user data to protected component.
      <PrivateRoute path="/protected" component={Protected} user={username:'ariful', email:'[email protected]'}/>
    </div>
  </Router>
);

const fakeAuth = {
  isAuthenticated: false,
  authenticate(cb) {
    this.isAuthenticated = true;
    setTimeout(cb, 100); // fake async
  },
  signout(cb) {
    this.isAuthenticated = false;
    setTimeout(cb, 100);
  }
};

const AuthButton = withRouter(
  ({ history }) =>
    fakeAuth.isAuthenticated ? (
      <p>
        Welcome!{" "}
        <button
          onClick={() => {
            fakeAuth.signout(() => history.push("/"));
          }}
        >
          Sign out
        </button>
      </p>
    ) : (
      <p>You are not logged in.</p>
    )
);

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      fakeAuth.isAuthenticated ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

const Public = () => <h3>Public</h3>;

// show the username here
const Protected = (props) => <h3>Protected Username: {props.user.username}</h3>;

class Login extends React.Component {
  state = {
    redirectToReferrer: false
  };

  login = () => {
    fakeAuth.authenticate(() => {
      this.setState({ redirectToReferrer: true });
    });
  };

  render() {
    const { from } = this.props.location.state || { from: { pathname: "/" } };
    const { redirectToReferrer } = this.state;

    if (redirectToReferrer) {
      return <Redirect to={from} />;
    }

    return (
      <div>
        <p>You must log in to view the page at {from.pathname}</p>
        <button onClick={this.login}>Log in</button>
      </div>
    );
  }
}

export default AuthExample;

How can I successfully send the user object to protected component?

like image 278
Ariful Haque Avatar asked Mar 01 '18 06:03

Ariful Haque


2 Answers

You need to pass on the ...rest params that you pass to PrivateRoute on to the component, however not all of them need to react the component. You can destructure other params that are needed by React router

const PrivateRoute = ({ component: Component, exact, strict, path, ...rest }) => (
  <Route
    exact={exact}
    strict={strict}
    path={path}
    render={props =>
      fakeAuth.isAuthenticated ? (
        <Component {...props} {...rest} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);
like image 122
Shubham Khatri Avatar answered Oct 30 '22 09:10

Shubham Khatri


See where the issue is:

<PrivateRoute 
   path="/protected" 
   component={Protected} 
   user={username:'ariful', email:'[email protected]'} />

Now inside PrivateRoute component, user object will get passed as props, it will be available in rest object, also rest will have the data that will be required for Route, so to make it more generic.

Instead of passing the user object always pass data, now rest will have the data required for Route and data will be the data passed to component, write it like this:

const PrivateRoute = ({ component: Component, data, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      fakeAuth.isAuthenticated ? (
        <Component {...props} {...data} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

Pass that data to <Component {...data} {...props} />

like image 23
Mayank Shukla Avatar answered Oct 30 '22 08:10

Mayank Shukla