Reputation: 821
In Gatsby, how would I restrict routes programmatically? Using react-router, I see it's possible to do a <Redirect>
with <Route>
, but how would this be implemented in Gatsby? To do something like this...
<Route exact path="/" render={() => (
loggedIn ? (
<Redirect to="/dashboard"/>
) : (
<PublicHomePage/>
)
)}/>
Where would I put this file in Gatsby? Would I put it in src/pages
or elsewhere?
Edited, asking for additional clarification...
I'm able to get this work per the advice from @Nenu and the Gatsby docs. The docs gave a non-asynchronous example, so I had to tweak it for interacting with a remote server like this...
async handleSubmit(event) {
event.preventDefault()
await handleLogin(this.state)
.then(response => _this.setState({isLoggedIn: isLoggedIn()}))
.catch(err => { console.log(err) });
}
Also, I am able to use the <PrivateRoute />
with this.
Unfortunately though, when I render using...
render() {
if (isLoggedIn()) {
return <Redirect to={{ pathname: `/app/profile` }} />
}
return (
<View title="Log In">
<Form
handleUpdate={e => this.handleUpdate(e)}
handleSubmit={e => this.handleSubmit(e)}
/>
</View>
)
}
...while I do indeed <Redirect to={{ pathname:
/app/profile}} />
, I notice that a split-second before I redirect, the form fields are emptied and only after that do I get redirected to /app/profile
(from /app/login
). Also, if I type in an incorrect password, my whole form is re-rendered (re-rendering <View />
again). This would be a bad user-experience because they they'd have to re-enter all of their info from scratch, plus I'd be unable to add styling for invalid inputs, etc. I'm wondering if there is a better way to do this with Gatsby.
Or, would I have to build form functionality more from scratch (i.e., using Redux, Router, etc more directly) rather than depending upon Gatsby's higher level of abstraction?
Upvotes: 3
Views: 6467
Reputation: 2657
Gatsby uses react-router under the hood, therefore you can define your client-only routes with it.
There is, as always with gatsby, a very nice example in the github repo:
https://github.com/gatsbyjs/gatsby/tree/master/examples/simple-auth
And the doc about it:
https://www.gatsbyjs.org/docs/building-apps-with-gatsby/#client-only-routes--user-authentication
To sum up, this is what is done:
PrivateRoute
component in /src/componentsconst PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
!isLoggedIn() ? (
// If we’re not logged in, redirect to the login page.
<Redirect to={{ pathname: `/app/login` }} />
) : (
<Component {...props} />
)
}
/>
);
Let suppose you want to restrict access of the /app/:path section of your website, then in /src/pages/app.js:
const App = () => (
<div>
<PrivateRoute path="/app/profile" component={Home} />
<PrivateRoute path="/app/details" component={Details} />
<Route path="/app/login" component={Login} />
</div>
);
These routes will exist on the client only and will not correspond to index.html files in an app’s built assets. If you wish people to visit client routes directly, you’ll need to setup your server to handle these correctly. (source)
exports.onCreatePage = async ({ page, boundActionCreators }) => {
const { createPage } = boundActionCreators
// page.matchPath is a special key that's used for matching pages
// only on the client.
if (page.path.match(/^\/app/)) {
page.matchPath = `/app/:path`
// Update the page.
createPage(page)
}
}
Upvotes: 7