Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Last active December 20, 2021 09:46
Show Gist options
  • Star 89 You must be signed in to star a gist
  • Fork 21 You must be signed in to fork a gist
  • Save ryanflorence/eba97731b5579a1c01702c9d394b3feb to your computer and use it in GitHub Desktop.
Save ryanflorence/eba97731b5579a1c01702c9d394b3feb to your computer and use it in GitHub Desktop.
let UserContext = React.createContext();
class App extends React.Component {
state = {
user: null,
setUser: user => {
this.setState({ user });
}
};
render() {
return (
<UserContext.Provider value={this.state}>
<Router>
<Home path="/" />
<About path="/about" />
<PrivateRoute as={Dashboard} path="/dashboard" />
</Router>
</UserContext.Provider>
);
}
}
class PrivateRoute extends React.Component {
static contextType = UserContext;
render() {
let { as: Comp, ...props } = this.props;
return this.context.user ? <Comp {...props} /> : <Login />;
}
}
class Login extends React.Component {
static contextType = UserContext;
render() {
return (
<form
onSubmit={async () => {
let user = await doWhateverYouNeedToDoToLogin();
this.context.setUser(user);
}}
/>
);
}
}
function Home() {
return <div>home</div>;
}
function About() {
return <div>about</div>;
}
function Dashboard() {
return <div>Protected dashboard</div>;
}
@cvrajeesh
Copy link

this is how I implemented PrivateRoute

const PrivateRoute = props => {
  const { user } = useUserContext();
  let { as: Comp, ...otherProps } = props;

  return user ? (
    <Comp {...otherProps} />
  ) : (
    <Redirect to="/login" replace={true} noThrow={true} />
  );
};

Make sure noThrow props is set to true otherwise you'll get exception when redirecting in development.

@markuckermann
Copy link

@christensen143 I like your hooks example but think

// PrivateRoute.js

const PrivateRoute = props => {
  const { user } = useContext(AuthContext);
  
  let { as: Comp, ...props } = props;
  return user ? <Comp {...props} /> : <Login />;
}

Should be

// PrivateRoute.js

const PrivateRoute = props => {
  const { user } = useContext(AuthContext);
  
  let { as: Comp, ...restOfTheProps } = props;
  return user ? <Comp {...restOfTheProps } /> : <Login />;
}

to avoid an Identifier 'props' has already been declared error.

@harenadata
Copy link

Make sure noThrow props is set to true otherwise you'll get exception when redirecting in development.

@cvrajeesh you fixed my problem. thank you!

@azamatsmith
Copy link

For the people that show up here for how to do this with nested routing, I solved it using nested routers:

// App.js

<Router>
   <Login path="/login" />
   <ForgotPass path="/forgot-password" />
   <PrivateRoute as={Dashboard} path="/dashboard/*" />
</Router>

// Dashboard
export default ({children}) => (
  <Router>
    <DashHome path="/" />
    <DashStatistics path="/statistics" />
  </Router>
)

@shennan
Copy link

shennan commented Nov 20, 2020

New to this. My <Router> moans that I don't have path as a prop in the children components I pass. What happens when you have dynamically created pages (like blog posts) in your gatsby-node.js? Can't I just have...

<Router>
  {authenticated && <PrivateRoute/>}
  {!authenticated && <PublicRoute/>}
</Router>

...and then not have to think about it further down the component tree? Rather than pepper my whole application with <Component path="path/to/something"/>?

Also, does <Router/> effectively stop Gatsby from serving static files?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment