Problem using useRoutes when redirecting with params - javascript

I am trying to set up my project for the first time using useRoutes and lazy loading with children. But I am having a problem that it won't load the children when redirected to that site? The Home page works perfectly fine.
https://codesandbox.io/s/great-rgb-ippuob?file=/src/Page/Home/index.js
Home path="/"
import React from "react";
import { Link } from "react-router-dom";
const Home = () => {
return (
<>
<h1>Hello Welcome to my beauty page</h1>
<Link to="/1">click me</Link>
</>
);
};
export default Home;
Children:
import React from "react";
import { useParams } from "react-router-dom";
const Id = () => {
const { id: loadingId } = useParams();
return <h1>Right now you are on the side of: {loadingId}</h1>;
};
export default Id;
App.js:
import "./styles.css";
import Route from "./Routes";
import { Suspense } from "react";
export default function App() {
return (
<>
<div className="App">
<Suspense fallback={<p>Loading...</p>}>
<Route />
</Suspense>
</div>
</>
);
}
Routes:
import { useRoutes } from "react-router-dom";
import React from "react";
export default function Router() {
return useRoutes([
{
path: "/",
element: <Home />,
children: [{ path: "/:id", element: <Id /> }]
}
]);
}
const Home = React.lazy(() => import("./Page/Home"));
const Id = React.lazy(() => import("./Page/Id"));
And in Index I have
<BrowserRouter>
<App />
</BrowserRouter>

You should add <Outlet /> in Layout/Parent component (Home for you)
const Home = () => {
return (
<>
<h1>Hello Welcome to my beauty page</h1>
<Link to="/1">click me</Link>
<Outlet />
</>
);
};
export default Home;

Related

The code from react-router-dom of the old version does not work on react-router-dom of the new version

I have a consts.js file
export const ADMIN_ROUTE = '/admin'
export const LOGIN_ROUTE = '/login'
export const REGISTRATION_ROUTE = '/registration'
export const SHOP_ROUTE = '/'
export const BASKET_ROUTE = '/basket'
export const DEVICE_ROUTE = '/product'
I have a routes.js file
import Admin from "./pages/Admin"
import Auth from "./pages/Auth"
import Basket from "./pages/Basket"
import DevicePage from "./pages/DevicePage"
import Shop from "./pages/Shop"
import {
ADMIN_ROUTE,
BASKET_ROUTE,
DEVICE_ROUTE,
LOGIN_ROUTE,
REGISTRATION_ROUTE,
SHOP_ROUTE
} from "./utils/consts"
export const authRoutes = [
{
path: ADMIN_ROUTE,
Component: Admin
},
{
path: BASKET_ROUTE,
Component: Basket
}
]
export const publicRoutes = [
{
path: SHOP_ROUTE,
Component: Shop
},
{
path: LOGIN_ROUTE,
Component: Auth
},
{
path: REGISTRATION_ROUTE,
Component: Auth
},
{
path: DEVICE_ROUTE + '/:id',
Component: DevicePage
},
]
App.js
import { BrowserRouter } from "react-router-dom";
import AppRouter from "./components/AppRouter";
function App() {
return (
<BrowserRouter>
<AppRouter/>
</BrowserRouter>
);
}
export default App;
AppRouter.js
import React from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import { authRoutes, publicRoutes } from '../routes';
const AppRouter = () => {
const isAuth = false;
return (
<Switch>
{isAuth && authRoutes.map(({path, Component}) =>
<Route key={path} path={path} component={Component} exact />
)}
{publicRoutes.map(({path, Component}) =>
<Route key={path} path={path} component={Component} exact />
)}
</Switch>
);
};
export default AppRouter;
I get the error, export 'Switch' (imported as 'Switch') was not found in 'react-router-dom'. I tried all variants, tried to replace Switch with Router and so on, but nothing helps. I know they removed Switch in react-router-dom#6.0, but I don't understand how to fix this code to make it work.
The Switch component was replaced by the Routes component in react-router-dom#6. Additionally the Route component API changed as well, instead of the component and render and children function props there is now a single element prop taking a React.ReactNode, a.k.a JSX, value.
Example:
import React from 'react';
import { Routes, Route } from 'react-router-dom';
import { authRoutes, publicRoutes } from '../routes';
const AppRouter = () => {
const isAuth = false;
return (
<Routes> // <-- Directly wrap all Route components
{isAuth && authRoutes.map(({path, Component}) => (
<Route
key={path}
path={path}
element={<Component />} // <-- ReactNode/JSX
/>
))}
{publicRoutes.map(({path, Component}) => (
<Route
key={path}
path={path}
element={<Component />} // <-- ReactNode/JSX
/>
))}
</Routes>
);
};
See the Migrate from v5 guide for more details on all the breaking changes from v5 to v6.

React 6.4.0 common header for all the router

I am starting react project with react-router-dom version 6.4.0, but not able to create common header for all the routes.
App.js - This is the file where I am adding RouterProvider
import logo from './logo.svg';
import './App.css';
import { Link, Outlet, RouterProvider } from "react-router-dom";
import { routers } from "./routes/routes";
function App() {
return (
<RouterProvider router={routers}>
<div>Header</div>
<Outlet />
</RouterProvider>
);
}
export default App;
routes.js - In this file I am going to create all the routes
import { createBrowserRouter, redirect } from "react-router-dom";
import About from "../pages/About/About";
import Home from "../pages/Home/Home";
import { getUser, isAuthenticated } from "../sso/authUtil";
const authLoader = () => {
if (!isAuthenticated()) {
return redirect("https://google.com");
} else {
return getUser();
}
};
export const routers = createBrowserRouter([
{
path: "/",
element: <Home />,
loader: authLoader,
},
{
path: "/about",
element: <About />,
},
]);
Home.js - This file is home page which will have the links to other pages along with header
import React from "react";
import { Link, Outlet, useLoaderData } from "react-router-dom";
const Home = () => {
const loaderData = useLoaderData();
return (
<>
<div>Header</div>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<div>Home: {loaderData}</div>{" "}
<Outlet />
</>
);
}
export default Home;
About.js - It is normal component which say about
import React from "react";
const About = () => {
return <div>About</div>;
};
export default About;
I want both Home and About component to be loaded with header on top.
Even in react-router-dom#6.4.0 rendering layout routes with common UI still works the same.
Create a layout route component that render the common header component and an Outlet for nested routes.
Example:
const Layout = () => (
<>
<CommonHeader />
<Outlet />
</>
);
Import and render Layout on a layout route in the configuration.
const routers = createBrowserRouter([
{
element: <Layout />,
children: [
{
path: "/",
element: <Home />,
loader: authLoader
},
{
path: "/about",
element: <About />
}
]
}
]);
...
function App() {
return <RouterProvider router={routers} />;
}

× ReferenceError: Home is not defined

I wanted to import react router to my components and got the error as described in the 'title'!
btw I'm doing it from a tutorial crash course!
I will show my files below
App.js
import { BrowserRouter, Route } from "react-router-dom";
import "./App.css";
import Header from "./components/Header";
import Home from "./Pages/Home";
import About from "./Pages/About";
import Profile from "./Pages/Profile";
function App() {
return (
<BrowserRouter>
<div className="App">
<Header />
</div>
<Route path="/" component={Home} exact />
<Route path="/about" component={About} />
<Route path="/profile" component={Profile} />
</BrowserRouter>
);
}
export default App;
Home.js
const Home = () => {
return <h1>Home Page</h1>;
};
export default Home;
About.js
const About = () => {
return <h1>About Page</h1>;
};
export default About;
Profile.js
const Profile = () => {
return <h1>Profile Page</h1>;
};
export default Profile;
Header.js
const Header = () => {
return (
<>
<h1>React Router Dom</h1>
</>
)
}
export default Header;
Are you sure that it is in "./Pages/Home" ? Can you try putting Home component code above
function App()
to see if it will show the same error

How to redirect a page to menu on reload or refresh page with react?

I want to redirect a user to the menu page when he reload or refersh the current page.
Menu.js:
import React from "react";
import { useHistory } from "react-router-dom";
export default function Menu() {
const history = useHistory();
const handleClick = () => {
history.push("/myComponent");
};
return (
<div>
<h1>Menu Page</h1>
<button onClick={handleClick}>Go to MyComponent</button>
</div>
);
}
MyComponent.js:
import React, { useEffect } from "react";
import { useHistory } from "react-router-dom";
export default function MyComponent() {
const history = useHistory();
const handler = function () {
history.push("/");
};
useEffect(() => {
window.addEventListener("beforeunload", handler);
return () => {
window.removeEventListener("beforeunload", handler);
};
}, []);
return (
<div>
<h1>My Component Page</h1>
</div>
);
}
App.js:
import { Router, Route } from "react-router-dom";
import Menu from "./Menu";
import MyComponent from "./MyComponent";
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default function App() {
return (
<Router history={history}>
<Route exact path="/" component={Menu} />
<Route exact path="/myComponent" component={MyComponent} />
</Router>
);
}
When I'm on MyComponent page and I reload the page the path url changed to '/' but the page displayes the content of MyComponent.
I want to be redirected only to Menu only when I refresh the page or reload it by click on reload page button on the browser. How can I fix that?
You need to add switch:
<Router history={history}>
<Switch>
<Route exact path="/" component={Menu} />
<Route exact path="/myComponent" component={MyComponent} />
</Switch>
</Router>
To fix this issue I created a new route RefreshRoute :
import React, {useCallback, useEffect} from 'react';
import {Redirect, Route} from 'react-router-dom';
const RefreshRoute = ({
component: Component,
redirectionPath,
...rest
}: Props) => {
redirectionPath = redirectionPath ?? '/';
const perf = performance.getEntriesByType('navigation')[0].toJSON();
const reloadType = perf.type !== 'reload';
const handler = useCallback((e) => {
e.preventDefault();
e.returnValue = '';
return true;
}, []);
useEffect(() => {
window.onbeforeunload = handler;
return () => {
window.onbeforeunload = handler;
};
});
return (
<>
{reloadType ? (
<Route component={Component} {...rest} />
) : (
<Redirect to={redirectionPath} />
)}
</>
);
};
export default RefreshRoute;
App.js:
import { Router, Route } from "react-router-dom";
import Menu from "./Menu";
import MyComponent from "./MyComponent";
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default function App() {
return (
<Router history={history}>
<Route exact path="/" component={Menu} />
<RefreshRoute path='/myComponent' redirectionPath='/' />
</Router>
);
}

React router 4 nesting routes alternative technique

On my attempt to do nested routes, I've failed to have the child components to mount when the route changes through Link or history.push; but if declaring the routes directly in the root.js file, it works. So, ideally I'd like to keep as much routes configuration as possible in the root/routes.js file and not all over the App (I'm iterating over the root/routes.js object instead to do this automatically; I mean... trying)
To break it down logically (it's a bit abstract, but check the code below afterwards please):
- There's a `root/routes.js` that has all the routes configuration (parents, nested components, etc)
- The `root.js` defines the `<Route...>` where the attribute `component` is the return value of a function that passes the `routes` configuration to its `routes` component prop
- the main wrapper iterates over the component prop `routes` and defines `child` routes automatically...I mean...I'm trying...
Why would I want to do this? The way my brain works and why not? Was possible before react router 4
<MyAppWrapper>
<CommonNavigationBar />
<Main>
----- dynamic / changes by route etc -----
</Main>
<Footer />
</MyAppWrapper>
I wonder where my attempt is failing?
// Working version
import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'
import App from '../app/containers/app'
const Root = ({store, history}) => {
return (
<Provider store={store}>
<BrowserRouter history={history}>
<Route path='/' component={App} />
</BrowserRouter>
</Provider>
)
}
export default Root
For the previous example, the App component as nested , bellow I'm trying to do that dynamically..and it fails for some reason! It should be exactly the same though...there must be a typoe somewhere...
like,
import React, { Component } from 'react'
import { isBrowser } from 'reactatouille'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { withRouter, Route } from 'react-router'
import Navbar from '../navbar'
import JourneySelector from '../journeySelector'
import reservationFinder from '../../../reservationFinder'
// include the stylesheet entry-point
isBrowser() && require('../../../../sass/app.scss')
class App extends Component {
constructor (props) {
super(props)
this.state = {
init: true
}
}
render () {
return (
<div className={'app' + ' ' + (!this.state.init && 'uninitialised')}>
<Navbar />
<main>
<Route exact path='/' component={JourneySelector} />
<Route exact path='/reservation-finder' component={reservationFinder.containers.App} />
</main>
</div>
)
}
}
// export default App
function mapStateToProps (state, ownProps) {
return {
// example: state.example
}
}
function matchDispatchToProps (dispatch) {
return bindActionCreators({
// replay: replay
}, dispatch)
}
export default connect(mapStateToProps, matchDispatchToProps)(withRouter(App))
While my technique fails (all I'm trying to do is iterate the root/routes children routes to generate these ):
// root/routes.js
import app from '../app'
import reservationFinder from '../reservationFinder'
const rootRoutes = [
{
path: '/',
component: app.containers.App,
exact: true,
routes: [{
path: '/',
exact: true,
component: app.containers.JourneySelector
}, {
path: '/reservation-finder',
component: reservationFinder.containers.App
}]
}
]
export default rootRoutes
The root js file. You see the setRoute fn returns a new component, where the children routes is passed as a props? I believed this would work:
// root.js
import React from 'react'
import { Route, Switch } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'
const setRoute = (route) => {
const MyComponent = route.component
return <Route key={route.path} exact={route.exact || false} component={() => (<MyComponent routes={route.routes} />)} />
}
const Root = ({store, history}) => {
return (
<Provider store={store}>
<BrowserRouter history={history}>
{ rootRoutes.map(route => setRoute(route)) }
</BrowserRouter>
</Provider>
)
}
export default Root
the main app that I want to use as a wrapper:
// main app
import React, { Component } from 'react'
import { isBrowser } from 'reactatouille'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { withRouter, Route } from 'react-router'
import Navbar from '../navbar'
// include the stylesheet entry-point
isBrowser() && require('../../../../sass/app.scss')
class App extends Component {
constructor (props) {
super(props)
this.state = {
init: true
}
}
render () {
return (
<div className={'app' + ' ' + (!this.state.init && 'uninitialised')}>
<Navbar />
<main>
{ Array.isArray(this.props.routes) && this.props.routes.map(route => <Route key={route.path} {...route} />) }
</main>
</div>
)
}
}
// export default App
function mapStateToProps (state, ownProps) {
return {
// example: state.example
}
}
function matchDispatchToProps (dispatch) {
return bindActionCreators({
// replay: replay
}, dispatch)
}
export default connect(mapStateToProps, matchDispatchToProps)(withRouter(App))
I understand I MIGHT be able to achieve something similar, like?!
// root
import React from 'react'
import { Route, Switch } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'
import MyAppWrapper from 'xxx/MyAppWrapper'
const setRoute = (route) => {
const MyComponent = route.component
return <Route key={route.path} exact={route.exact || false} component={() => (<MyComponent routes={route.routes} />)} />
}
const Root = ({store, history}) => {
return (
<Provider store={store}>
<BrowserRouter history={history}>
<MyAppWrapper>
<Route path='x' component={x} />
<Route path='y' component={y} />
</MyAppWrapper>
</BrowserRouter>
</Provider>
)
}
export default Root
Notes: During testing, I've noticed that it worked server-side? I mean, I may have missed something, and I didn't save my work. Also, when it fails, the previous component (the default) is still mounted and does not unmount
I even tried (without sucess...I wonder if this is a bug):
import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import App from '../app/containers/app'
import rootRoutes from './routes'
const Root = ({store, history}) => {
return (
<Provider store={store}>
<BrowserRouter history={history}>
<Route path='/' render={() => (
<App />
)} />
</BrowserRouter>
</Provider>
)
}
export default Root
Ok, I think this is a bug so reported ( https://github.com/ReactTraining/react-router/issues/5190 ), you can find the live example here ( https://codepen.io/helderoliveira/pen/rmXdgd ), click topic. Maybe what I'm trying to do is not supported, but instead of blank we should get an error message.
Ok, I found the typo. The solution is to use render and pass the routerProps + any other props you desire through Object.assign and the spread operator!
// root.js
import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import App from '../app/containers/app'
import rootRoutes from './routes'
const Root = ({store, history}) => {
return (
<Provider store={store}>
<BrowserRouter history={history}>
<Route path='/' render={routeProps => <App {...Object.assign({}, routeProps, { routes: rootRoutes[0].routes })} />} />
</BrowserRouter>
</Provider>
)
}
export default Root
And the main app wrapper:
class App extends Component {
render () {
return (
<div className={'app kiosk' + ' ' + (!this.state.init && 'uninitialised')}>
<Navbar />
<main>
{ Array.isArray(this.props.routes) && this.props.routes.map(route => <Route key={route.path} exact={route.exact} path={route.path} component={route.component} />) }
</main>
</div>
)
}
}
export default App
the routes file:
import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'
const setRoute = (route) => {
const MyComponent = route.component
return <Route key={route.path} path={route.path} render={routeProps => <MyComponent {...Object.assign({}, routeProps, { routes: rootRoutes[0].routes })} />} />
}
const Root = ({store, history}) => {
return (
<Provider store={store}>
<BrowserRouter history={history}>
<div>
{ rootRoutes.map(route => setRoute(route)) }
</div>
</BrowserRouter>
</Provider>
)
}
export default Root

Categories

Resources