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

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.

Related

404 page not working for nested routes in react

I'm currently working on a notes app in React and I've built a 404 page and now if I go to a route that doesn't exist it shows a 404 page
for example, if I go to the route /get-the-note/ I get a 404 page.
But the problem is that I have a route:
<Route exact path="/single-note/:id" component={Singlenote}></Route>
which needs an id and if I put the correct id like I have a note with id no 2 and if I go to the route /single-note/2 it works but if I put an id that doesn't exist like if I put an id 120 which doesn't exist and I go to the route /single-note/120 I get a plain page instead of a 404 page. I want it show the 404 page even if the id is incorrect
here is my app.js file:
import "./App.css";
import Homepage from "./components/homepage.component";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Singlenote from "./components/singlenote.component";
import PageNotFound from "./components/404_page";
function App() {
return (
<Router>
<Switch>
<Route exact path="/" component={Homepage} />
<Route exact path="/single-note/:id" component={Singlenote}></Route>
<Route path="*"><PageNotFound /></Route>
</Switch>
</Router>
);
}
export default App;
and here is my 404 page:
import React from 'react'
const PageNotFound = () => {
return (
<div id="wrapper">
<img src="https://i.imgur.com/qIufhof.png" />
<div id="info">
<h3>This page could not be found</h3>
</div>
</div >
)
}
export default PageNotFound
The router has no way of knowing which IDs do and do not exist.
It's up to your Singlenote to render 404 content if there is no such ID.
For the last route in the Switch, you don't need the path at all, by the way.
<Route component={PageNotFound} />
The approach I suggest for this is by modifying your Singlenote component, with a useEffect hook, that checks if the id provided exists or not, only once on mount (useEffect(() => { code for check }, []);). In the event that the id does not exist, you can redirect the execution to your 404 component, by using history (e.g. history.push('*'), where * is used as the path to redirect to, you could use something else that is not covered in the routes, so it will go to 404).
I have to add that this is not a good approach, I would personally go with a notification or other indicator displayed when accessing your Singlenote component with an id that does not exist (again with useEffect), which informs the user that no results or data were found for the given id.

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

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>
);
}

React routeer is causing a blank index page. Next JS

I'm creating a website, and I want the users to be directed to a specific page when they open the site. The page they are going to be directed to depends on if they already logged in. My problem is: the router doesn't work (user is not redirected to any page) and all that appears is a blank page. I've tried to get rid of the routes, but even though, I couldn't display anything on the index page. Maybe the problem is not even the router, but something else.
I never get any error messages. Here are the parts of the code, where I think the problem may be.
_app.js:
import React from 'react'
import { BrowserRouter as Router, Route } from "react-router-dom"
import Novidades from './lancamento'
import SignUp from './signup'
import Croosa from './croosa'
import { AuthProvider } from '../utils/auth'
import PrivateRoute from '../utils/PrivateRoute'
const App = () => {
return(
<AuthProvider>
<Router>
<div>
<PrivateRoute exact path='/lancamento' component={Lancamento} />
<Route exact path='/croosa' component={Croosa}/>
<Route exact path='/signup' component={SignUp} />
</div>
</Router>
</AuthProvider>
)
}
export default App
index.js:
import React from 'react'
import App from './_app'
export default function Home() {
return(
<App/>
)
}
And the PrivateRoute.js, which decides to which page the user is going to be redirected:
import React, { useContext } from "react";
import { Route, Redirect } from "react-router-dom";
import { AuthContext } from "./auth";
const PrivateRoute = ({ component: RouteComponent, ...rest }) => {
const {currentUser} = useContext(AuthContext);
return (
<Route
{...rest}
render={routeProps =>
!!currentUser ? (
<RouteComponent {...routeProps} />
) : (
<Redirect to={"/signup"} />
)
}
/>
)
}
export default PrivateRoute
I would appreciate it if someone could point out my mistake(s).
Next.js uses a filesystem based routing structure.
You have a misunderstanding of how the _app.js file works. It's the parent component that is responsible for rendering the other components that get exported from other pages.
For example: if my _app.js file looks like this:
export default function App({ Component, pageProps }) {
return (
<div>
<p>This was injected by _app.js</p>
<Component {...pageProps} />
<div>
);
}
and my pages/index.js file looks like this:
export default function Hello(){
return <h1>Hello World!</h1>
}
With that setup if I visit the localhost:3000/ then the following will get rendered
<div>
<p>This was injected by _app.js</p>
<h1>Hello World!</h1>
</div>
What you did instead is in your _app.js you ignored the Component property that was passed and so on every page you visit the same content will be rendered. That is:
<AuthProvider>
<Router>
<div>
<PrivateRoute exact path="/lancamento" component={Lancamento} />
<Route exact path="/croosa" component={Croosa} />
<Route exact path="/signup" component={SignUp} />
</div>
</Router>
</AuthProvider>
The reason your index page is blank is because you didn't set up a route for / and so no component will be rendered by react router on that page. Regardless I suggest you stop using react router and start using the built in routing system with next.js

React router redirect re-rendering the same component it is called from, not redirected to the specified path

I am trying to redirect to a component from another one, after a state change using
in Component B.js, I want a redirect onclick as below:
if(this.state.something) return <Redirect to= "/" />
in Component A.js
`
import { Route,Switch,BrowserRouter as Router} from 'react-router-dom';
const ComponentA = () => {
return (
<Router>
<React.Fragment>
<Switch>
<Route exact path="/somepath/:name/:id/" component={ComponentXYZ} />
<Route path='/' exact component={Log} />
</Switch>
</React.Fragment>
</Router>
)} ;
export default ComponentA ;`
My problem is that the on redirect the URL changes to 'localhost:3000/' but the component A is rendering the route with component 'abc' instead of 'Log'. If I refresh the browser, the Log component renders and displays the view. I tried history.push and also withRouter to solve the issue, but no luck. Kindly help,I'm new to react programming. TIA :)

React Router v4 programmatic redirect: Warning when redirecting to the "same route"

I have a React app that has a basic structure like seen below. I am attempting to programmatically redirect the user to /profile route but I am seeing Warning: You tried to redirect to the same route you're currently on: "/profile".
Inside the Main component header I have a form that should redirect the user to /profile. The only way that I was able to get this working is to add && this.props.location.pathname !== '/profile' to the state.toProfile condition. This feels a bit dirty. It seems like there is a better way.
I am taking the approach recommended in this blog post https://tylermcginnis.com/react-router-programmatically-navigate/, it seems like this doesn't work if the route you redirect to contains the same component as the route that was redirected from.
class App extends Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route path="/dashboard" component={Dashboard} />
<Route component={Main} />
</Switch>
</BrowserRouter>
);
}
}
class Main extends Component {
state = {
toProfile: false
}
render() {
if (this.state.toProfile === true) {
return <Redirect to='/profile' />
}
return (
<header>
...
</header>
);
}
}
you need to add a route for /profile, atm profile goes to Main that goes to /profile... again

Resources