React Router always renders NotFound default component - javascript

I've been searching all over the internet for solutions but alas I come here for some help. The problem is that the URL changes but the respective component in Route don't render, instead of that, the NotFoundPage is rendered.
Here's the App.js Router code:
<Router history={history}>
<Switch>
<PrivateRoute exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Route component={NotFoundPage}/>
</Switch>
</Router>
Here's PrivateRoute code:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
localStorage.getItem('user')
? <Component {...props} />
: <Redirect to={{ pathname: '/login', state: { from: props.location } }} />
)} />
)
The problem I'm facing is the when I go to / the NotFoundPage is rendered instead of LoginPage but the URL correctly redirects and changes to /login. But when I refresh, the LoginPage is rendered. Similarly, when I click on link that takes to /register from LoginPage the URL changes but RegisterPage doesn't render it's the same NotFoundPage.

During contribution on github we figured solution.
This weird behavior flows from using custom history.
const customHistory = createBrowserHistory();
ReactDOM.render(<Router history={customHistory} />, node);
When it is used then somehow router don't react to changes in a location path.
Until you don't add:
<Switch location={window.location}>
According to the docs the location in switch by default is set to window. location but for some reason when you don't use BroswerRouter or StackRouter but just Router this starts working when we directly set location.

Related

Redirection in React Router Dom v6

What is the correct process for re-directions in v6? I was previously using the following code in v5, which was working fine:
<Route path="/login">
{user ? <Redirect to="/" /> : <LoginStandard />}
</Route>
However, I would like to use the same logic in this version. When my user has logged in, I would like to re-direct.
<Route path="/login">
<Route index element={<LoginStandard />} />
</Route>
Use the Navigate component to redirect. The conditional rendering logic still needs to be applied and components rendered out on the Route component's element prop.
Example:
<Route
path="/login"
element={user ? <Navigate to="/" replace /> : <LoginStandard />}
/>
It is often considered better practice to abstract this into a custom route protection component that conditionally renders an Outlet for nested routes or the Navigate component.
Example:
import { Navigate, Outlet } from 'react-router-dom';
const AnonymousRoute = ({ user }) => user
? <Navigate to="/" replace />
: <Outlet />;
...
<Route element={<AnonymousRoute user={user} />}>
<Route path="/login" element={<LoginStandard />} />
... other anonymous routes ...
</Route>
... other routes
With React Router Dom v6, you redirect with Navigate and useNavigate instead of Redirect and useHistory used in v5. Something like below. See the comments:
import { Navigate, useNavigate } from "react-router-dom";
export default function Foo() {
const navigate = useNavigate();
// Use navigate returned by useNavigate when you are outside of JSX
navigate("/");
// Use Navigate the imported component when you are inside of JSX
return <Route path="/login">{user ? <Navigate to="/" /> : <LoginStandard />}</Route>;
}

Why my components don't display on my React page?

So I'm learning React and building an app with multiple pages, I made a Routes file which looks like this:
import 'swiper/swiper.min.css';
import React from "react";
import { Route, Routes } from "react-router-dom";
import Home from "../pages/Home";
import Catalog from "../pages/Catalog";
import Detail from "../pages/Detail";
const Router = () => {
return (
<Routes>
<Route
path='/:category/search/:keyword'
component={Catalog}
/>
<Route
path='/:category/:id'
component={Detail}
/>
<Route
path='/:category'
component={Catalog}
/>
<Route
path='/'
exact
component={Home}
/>
</Routes>
);
}
And App.js looks like this:
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Header from './components/header/Header';
import Footer from './components/footer/Footer';
import Router from './config/Router';
function App() {
return (
<BrowserRouter>
<Routes>
<Route render={props =>{
<>
<Header {...props}/>
<Router/>
<Footer/>
</>
}}/>
</Routes>
</BrowserRouter>
);
}
export default App;
As you see, I have a browser router and Route which passes props to a component(as I understood) but for some reason the components don't display on the page(original components just have with their name inside of them, but they don't display in App.js).
And my console also says:
No routes matched location "/"
In routes.jsx file. I'm guessing it should lead to main page, but for some reason the route doesn't match and components in App.js don't display.
In Version 6.0.0 there is not any component prop in Route. It has been changed to element. So you need to change your Router to :
const Router = () => {
return (
<Routes>
<Route
path='/:category/search/:keyword'
element={Catalog}
/>
<Route
path='/:category/:id'
element={Detail}
/>
<Route
path='/:category'
element={Catalog}
/>
<Route
path='/'
exact
element={Home}
/>
</Routes>
);
}
As you've said you're using react-router-dom 6.0.2, and it seems that the tutorial you are following is for the older version (5?). There were some breaking changes in version 6.
You need to change your Router component to use element instead of component:
const Router = () => {
return (
<Routes>
<Route path="/:category/search/:keyword" element={<Catalog />} />
<Route path="/:category/:id" element={<Detail />} />
<Route path="/:category" element={<Catalog />} />
<Route path="/" exact element={<Home />} />
</Routes>
);
};
and also your App component seems to be getting in the way with the nested route.
I think it can be simplified to:
function App() {
return (
<BrowserRouter>
<>
<Header />
<Router />
<Footer />
</>
</BrowserRouter>
);
}
You can see a working demo on stackblitz

How to redirect to another Page using a button in Reactjs

I am trying to learn how to redirect through pages using React.
I have tried to write some code on my own but i keep getting problems. I Created a route class for the class path, and 2 classes to move through. And the route class is imported to the app class. I am not pasting any data from the second class because its a written paragraph to be displayed.
This is what i have done:
import React from 'react'
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import Firsttry from './firsttry'
import Comp2 from "./comp2";
const Routes = () => (
<Router>
<Switch>
<Route path="/" component={Firsttry} />
<Route path="/comp2" component={Comp2} />
</Switch>
</Router>
);
export default Routes;
Second class:
import React, { Component } from "react";
import { Redirect } from "react-router-dom";
class Firsttry extends Component {
constructor(props) {
super(props);
this.state = {
redirect: false
};
}
onclick = () => {
this.setState({
redirect: true
});
};
render() {
if (this.state.redirect) {
return <Redirect to="/comp2" />;
}
return (
<div>
<p> hello</p>
<button onClick={this.onclick}>click me</button>
</div>
);
}
}
export default Firsttry;
Switch the routes. May be always your first route is getting hit and Comp2 is never rendered.
<Switch>
<Route path='/comp2' component={Comp2} />
<Route path='/' component={Firsttry}/>
</Switch>
Or you have another option: adding exact prop to your route.
<Switch>
<Route exact path='/' component={Firsttry}/>
<Route exact path='/comp2' component={Comp2} />
</Switch>
Only one Route inside a Switch can be active at a time, and / will match every route. You can add the exact prop to the / route to make sure it will only match on the root path.
const Routes = () => (
<Router>
<Switch>
<Route exact path="/" component={Firsttry} />
<Route path="/comp2" component={Comp2} />
</Switch>
</Router>
);

Matched route not changing on routing hash change

I'm using react-router-dom with react-router-redux and history to manage routing for my app. I'm also using hash history for support on legacy browsers. Below are my route components:
<Switch>
<Route exact path={'/'} component={...} />
<Route path={'/a'} component={...} />
<Route path={'/b'} component={...} />
</Switch>
My app lands at the location: http://something.com/index.html#/, and correctly is routed to the first Route component. However, when using dispatch(push('/a')) in a thunk action creator to attempt to programatically switch routes, I'm finding that the proper route is not being matched.
I'm having a difficult time debugging this... any ideas? I'm thinking it perhaps has to do with the fact that my window.location.pathname is /index.html.
Switch receive a location prop, or must be wrapped with Router component. You can find more information at https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md#children-node/
If a location prop is given to the , it will override the location prop on the matching child element.
So try one of these ways:
class Example extends Component {
render() {
return (
<Switch location={this.props.location}>
<Route exact path={'/'} component={...} />
<Route path={'/a'} component={...} />
<Route path={'/b'} component={...} />
</Switch>
);
}
// location is react-router-redux reducer
export default connect(state => ({location: state.location}))(Example);
Or, another way you can do, it's wrap your Switch component with Router component (I pasted code from one of my project):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import configureStore from './store/configureStore';
const history = createHistory();
const store = configureStore(history);
// We wrap Switch component with ConnectedRouter:
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<Switch>
<Route exact path={'/'} component={...} />
<Route path={'/a'} component={...} />
<Route path={'/b'} component={...} />
</Switch>
</ConnectedRouter>
</Provider>,
document.getElementById('root')
);
More information about Router components you can find here: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Router.md

React-Router onChange hook

I am having issues getting the onChange hook in react-router to work properly. Here is my routes file:
import React from 'react';
import { Router, Route, browserHistory } from 'react-router';
import TestOne from './Pages/testone';
import TestTwo from './Pages/testtwo';
function logUpdate() {
console.log('Current URL: ' + window.location.pathname);
}
const Routes = (
<Router history={browserHistory}>
{/* App Routes */}
<Route path="/" component={App} lang={lang}>
<Route path="/testone" component={TestOne} onUpdate={logUpdate} />
<Route path="/testtwo" component={TestTwo} onUpdate={logUpdate} />
</Route>
</Router>);
export default Routes;
My understanding is, that the function logUpdate will be triggered on each state change. However, it is only triggered when I reload the corresponding page via F5.
My menu is using simple Links e.g.:
<div>
<Link to="/testone">Test One</Link>
<Link to="/testtwo">Test Two</Link>
</div>
What am I doing wrong?
onUpdate needs to be declared on the Router instance not Routes. Although, Routes can declare onChange and onEnter hooks - it's probably what you were looking for.
I'm using react-router ^2.4.0 and onUpdate did not work for me. I have instead used onChange on my base Route component.
const Routes = (
<Router history={browserHistory}>
{/* App Routes */}
<Route path="/" component={App} lang={lang} onChange={logUpdate}>
<Route path="/testone" component={TestOne} />
<Route path="/testtwo" component={TestTwo} />
</Route>
</Router>);

Categories

Resources