React-router-dom access pages only from app not from url - reactjs

I'm new to react, react-router-dom and redux.
I'm wondering if I can add an route that can't be acceses from url, only from application.
Use case is that I'm tryng to build registration form page which will on succesfull registration send an verification code to email and application will redirect to page to enter that verification code.
I was thinking of making new verification code page but that page can not be accesssed from typing it in url, it should be accesed only from application.
Is that possible or should I take another aproach?

In my opinion it's not a problem to have your "enter verification code" page be accessible from the URL. But if you want to do this then yes it can be done.
The render component for your verification page needs to check some condition. If that condition is met then it loads the page. If not, it renders a <Redirect/> to your form page.
I am using a property in location.state as that condition. When you navigate within the app then you will pass this property in you <Link/> component by using a to object instead of just a path string.
<Link to={{ pathname: "/verify", state: { fromApp: true } }}>Verify</Link>
The component for the verification page will use the useLocation hook to access the current location and see if the location state includes the fromApp property which we set.
const location = useLocation();
if (!location.state?.fromApp) {
return <Redirect to="/" />;
}
I created a very simple CodeSandbox demo.
You get redirected if you go to "/verify" directly. But you can access it just fine by clicking on the "Verify" link from the home page.
Complete Code:
import {
BrowserRouter,
Link,
Redirect,
Route,
Switch,
useLocation
} from "react-router-dom";
const Home = () => (
<div>
<h1>Home</h1>
<Link to={{ pathname: "/verify", state: { fromApp: true } }}>Verify</Link>
</div>
);
const VerificationPage = () => {
const { state } = useLocation();
if (!state?.fromApp) {
return <Redirect to="/" />;
}
return (
<div>
<h1>Enter Verification Code</h1>
<input />
<button>Submit</button>
</div>
);
};
export default function App() {
return (
<BrowserRouter>
<Switch>
<Route path="/verify" component={VerificationPage} />
<Route path="/" component={Home} />
</Switch>
</BrowserRouter>
);
}

Related

How to make default route to login page if not authenticated react-router-dom

I have an application where the first thing(default route) a user sees is a landing page with a register or login form if that user is not authenticated, if a user is authenticated I want to show the dashboard, (similar to how social media works) I have created 2 layouts <IsAuthenticated /> (where i render everything i want user that is authenticated to see) and an <Authentication /> (where i render the landing page with register and login forms), i'm having a really hard time making the logic how to use react router with this, If you know a tutorial suggestion where they handle this type of routing would be great
You can do something like this
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={(props) =>
isLogin ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: props.location },
}}
/>
)
}
/>
);
This function will redirect to the login page if the user isn't authenticated (change your AuthContext according to yours).
You can do the opposite for public route that shouldn't be accessible if the user is logged in (the login page for exemple).
const PrivateRoute = (props) => {
const { children } = props;
let auth = useContext(AuthContext);
let location = useLocation();
if (!auth.isLoggedIn) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return <>{children}</>;
};
In your routes :
<Route
path="/MY_SECRET_ROUTE"
element={
<PrivateRoute>
<MySecretComponent />
</PrivateRoute>
}
>

Conditional Redirection to a URL in react

I am building a "Forgot password" page. Following is the flow of my code:
A page with url /auth/forgot-password opens on clicking on Forgot Password.
It takes input as email and sends OTP to the registered email(if it exists in DB).
After sending OTP, it redirects to a new URL /auth/new-password.
Here, the remaining details are entered(ex. OTP,new password etc.)
Due to this flow, the user can access the path /auth/new-password by searching for it. But I don't want that to happen. User should only reach this url via /auth/forgot-password. User should be redirected to /auth/forgot-password URL if user searches for the prior one.
Currently in my Routes page I am doing this:
<ContentRoute path="/auth/forgot-password" component={ForgotPassword}/>
<ContentRoute path="/auth/new-password" component={NewPassword} />
Due to some restrictions I can't change the existing flow of the code.
How can I change this to exhibit the behavior explained above?
The easiest way is to create a HOC (Higher Order Component).
When I want a user to authenticate before accessing a sites' page, I always create a HOC called AuthRoute like this.
AuthRoute.js
import { connect } from "react-redux";
import { Redirect, Route } from "react-router-dom";
const AuthRoute = props => {
const { authUser, location } = props;
if(!authUser) {
return <Redirect to={{
pathname: "/",
state: { prevLoc: location.pathname }
}} />
}
return <Route {...props} />;
};
function mapStateToProps({ authUser }) {
return {
authUser
}
}
export default connect(mapStateToProps)(AuthRoute);
Then include that to the App component like this.
App.js
import { Fragment } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import AuthRoute from './components/AuthRoute'; // AuthRoute Import
import Dashboard from './components/Dashboard';
const App = () => {
return (
<Router>
<Switch>
{/* Include the AuthRoute component for the relevant page */}
<AuthRoute path="/home" component={Dashboard} />
<Route path="/" component={Login} />
</Switch>
</Router>
)
}
This implementation will check whether the user entered their email address on /auth/forgot-password page.
Completed project with HOC implementation - https://github.com/yushanwebdev/reactnd-would-you-rather

React Router v4 - Redirect to home on page reload inside application

I need to redirect to home page when user refreshes other pages inside my application. I am using React router v4 and redux. Since the store is lost on reload, the page user reloaded is now empty and hence I want to take him back to a page that does not need any previous stored data. I don't want to retain state in localStorage.
I tried to handle this in event onload but it did not work:
window.onload = function() {
window.location.path = '/aaaa/' + getCurrentConfig();
};
You can try creating a new route component, say RefreshRoute and check for any state data you need. If the data is available then render the component else redirect to home route.
import React from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";
const RefreshRoute = ({ component: Component, isDataAvailable, ...rest }) => (
<Route
{...rest}
render={props =>
isDataAvailable ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/home"
}}
/>
)
}
/>
);
const mapStateToProps = state => ({
isDataAvailable: state.reducer.isDataAvailable
});
export default connect(mapStateToProps)(RefreshRoute);
Now use this RefreshRoute in your BrowserRouter as like normal Route.
<BrowserRouter>
<Switch>
<Route exact path="/home" component={Home} />
<RefreshRoute exact path="dashboard" component={Dashboard} />
<RefreshRoute exact path="/profile" component={ProfileComponent} />
</Switch>
</BrowserRouter>
It is so amazing that you don't want to keep state of user route map in browser but you use react-router!, the main solution for your case is do not use react-router.
If you don't use it, after each refresh the app come back to main view of app, If you wanna see route map in address bar without any reaction use JavaScript history pushState.
Hope it helps you.

How to properly render a 404 page in React with React-Router?

I'm building a website with React and using React-Router, I'd like to render a 404 page when a url is visited by the user that doesn't exist.
Some urls are dynamic, say,
www.site.com/user/(username)
How do I render a 404 page with react-router if the user with a particular username doesnt exist? Do I have to manually write code in the component itself during the API calls to check if user exists and then redirect the user to the 404 component?
I'm looking for the best way to redirect the user to a not found page. Looking for ideas on how to do it best.
Use Switch then Redirect
https://reacttraining.com/react-router/web/example/no-match
https://reacttraining.com/react-router/web/api/Redirect
Valid URL no redirect: /user/valid_username
404 URL redirects: /user/invalid_username
import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
class App extends Component {
render() {
return (
<Router>
<div>
<Switch>
<Route path="/user/:username" component={Child} />
<Route path="/404" component={NoMatch} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
)
}
}
function Child({ match }) {
// perform some username check
if (match.params.username !== 'valid_username') {
return (
<div>
<Redirect to="/404" />
</div>
)
}
return (
<div className="App">
<h3>ID: {match.params.username}</h3>
</div>
)
}
function NoMatch({ location }) {
return (
<div>
<h3>
404 - No match for <code>{location.pathname}</code>
</h3>
</div>
)
}
export default App
You could check to see if this.props.match.username exists. If it does then render as normal if it doesnt then use React-Router Redirect Component to redirect to a 404 component. If you have multiple paths that require this functionality then you may consider making a HOC for this purpose.

How to properly Redirect with React Router 4?

A little background. I am using Firebase Authentication (GitHub, Twitter and Facebook), when the user gets authenticated, the app should redirect to Updater component from the SocialButtonList component.
Now I am trying to use Redirect to: string when the user gets authenticated, but for some reason is not working, maybe I am misunderstanding the docs.
My top level container
const App = () => {
return (
<Router>
<div>
<Switch>
<Route path='/updater' component={Updater} />
<Route exact path='/' component={Login} />
<Route component={NoMatch}/>
</Switch>
</div>
</Router>
);
}
Login.js
const Home = () => {
return (
<Content align='center'>
...
<SocialButtonList size={SOCIAL_BUTTON_SIZE_BIG} />
...
</Content>
);
}
SocialButtonList.js
This component handles the authentication logic and upon authenticating I call authHandler and from here I am attempting to redirect to the 'Updater' component.
authHandler = authData => {
if (authData) {
<Redirect to='/updater' />
console.log('AUTHENTICATED');
} else {
console.info('User is signed out!');
}
}
In console I can see AUTHENTICATED message, but the app does not redirect. How can I properly redirect to Updater component?
Update I found a way to redirect using withRouter. See my answer below in the answer section.
Well, I found my answer using withRouter instead of Redirect
import { withRouter } from 'react-router-dom';
...
authHandler = authData => {
if (authData) {
//<Redirect to={Updater} />
this.props.history.push('/updater');
console.log('AUTHENTICATED');
} else {
console.info('User is signed out!');
}
}
...
export default withRouter(SocialButtonList);
This successfully redirects to Updater component.
Now I am wondering, is there a way to get Redirect to work?

Resources