how to Route parent to child component in react router dom - javascript

I have an admin dashboard you can check to hear
I want to that if the admin clicks in user(You can see in the screenshot) then it will render the user page and other pages I trying to implement Nested Routeing But not working please if anyone can help it will be appreciated
if someone knows how to render child components and implement them in App.js Please Tell me
Admin.js
import React from 'react'
import { useState } from "react";
import "../AllStyle.css";
import {FaHouseUser, FaTasks, FaUser, FaBars} from "react-icons/fa"
import { NavLink } from 'react-router-dom'
import { AnimatePresence, motion } from "framer-motion";
import SidebarMenu from './SidebarMenu'
const routes = [
{
path: "/user",
name: "Users",
icon: <FaHouseUser />,
},
{
path: "/project",
name: "Project",
icon: <FaTasks />,
},
{
path: "/login",
name: "Logout",
icon: <FaUser />,
},
];
const Admin = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
const showAnimation = {
hidden: {
width: 0,
opacity: 0,
transition: {
duration: 0.5,
},
},
show: {
opacity: 1,
width: "auto",
transition: {
duration: 0.5,
},
},
};
return (
<>
<div className="main-container">
<motion.div
animate={{
width: isOpen ? "200px" : "45px",
transition: {
duration: 0.5,
type: "spring",
damping: 10,
},
}}
className={`sidebar `}
>
<div className="top_section">
<AnimatePresence>
{isOpen && (
<motion.h1
variants={showAnimation}
initial="hidden"
animate="show"
exit="hidden"
className="logo"
>
Evalue portal
</motion.h1>
)}
</AnimatePresence>
<div className="bars">
<FaBars onClick={toggle} />
</div>
</div>
<section className="routes">
{routes.map((route, index) => {
if (route.subRoutes) {
return (
<SidebarMenu
setIsOpen={setIsOpen}
route={route}
showAnimation={showAnimation}
isOpen={isOpen}
/>
);
}
return (
<NavLink
to={route.path}
key={index}
className="link"
// activeClassName="active"
>
<div className="icon">{route.icon}</div>
<AnimatePresence>
{isOpen && (
<motion.div
variants={showAnimation}
initial="hidden"
animate="show"
exit="hidden"
className="link_text"
>
{route.name}
</motion.div>
)}
</AnimatePresence>
</NavLink>
);
})}
</section>
</motion.div>
<main>{children}</main>
</div>
</>
);
};
export default Admin
App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './components/Home';
import Navbar from './components/Navbar';
import Contact from './components/Contact';
import Service from './components/Service'
import Login from './components/Login';
// Redirect to their dashboar
import Admin from './components/dashboard/admin/Admin';
import Employee from './components/dashboard/Employee';
import Publisher from './components/dashboard/Publisher';
//Toast error message show
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import Reset from './components/Reset';
import Newpassword from './components/Newpassword';
//admin Routes
import User from './components/dashboard/admin/pages/User'
import Project from './components/dashboard/admin/pages/Project'
function App() {
return (
<div>
<Router>
<Navbar/>
<Routes>
<Route exact path="/" element={<Home/>} />
<Route exact path="/service" element={<Service/>} />
<Route exact path="/contact" element={<Contact/>} />
<Route exact path="/login" element={<Login/>} />
<Route exact path="/reset" element={<Reset/>} />
<Route exact path="/reset/:token" element={<Newpassword/>} />
{/* Redirect to their dashboard */}
<Route exact path="/admin" element={<Admin/>} />
<Route exact path="/employee" element={<Employee/>} />
<Route exact path="/publisher" element={<Publisher/>} />
</Routes>
</Router>
{/* admin routes*/}
<Router>
{/* <Admin> For the admin children route to render children*/}
<Routes>
<Route path="/user" element={<User />} />
<Route path="/project" element={<Project />} />
</Routes>
{/* </Admin> */}
</Router>
<ToastContainer
position="top-right"
autoClose={4000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
</div>
);
}
export default App;

You can use Outlet component.
Example of implementation:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import { AuthProvider } from "./utils/context/auth";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<App />
</AuthProvider>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
app.js
import React from "react";
import { Route, Routes } from "react-router-dom";
import { useAuth } from "./utils/context/auth";
import "react-toastify/dist/ReactToastify.css";
import "./index.css";
import LoginPage from "./app/pages/Auth/Login";
import NotFoundPage from "./app/pages/NotFound/NotFound";
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
const App = () => {
const { checkingSession, isAuthenticated } = useAuth();
if (checkingSession) {
return <Loading />;
}
return (
<>
<Navbar />
<Routes>
{checkingSession || !isAuthenticated ? (
<Route path={"/"} element={<LoginPage />} />
) : (
<Route path="/admin" element={<Layout />}>
<Route path={"/admin"} element={<Dashboard />} />
<Route path={"/admin/project"} element={<Project />} />
</Route>
)}
<Route path={"/*"} element={<NotFoundPage />} />
<ToastContainer
position="top-right"
autoClose={4000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
</Routes>
</>
);
};
export default App;
layout.js
import React from 'react'
import { useState } from "react";
import "../AllStyle.css";
import {FaHouseUser, FaTasks, FaUser, FaBars} from "react-icons/fa"
import { NavLink } from 'react-router-dom'
import { AnimatePresence, motion } from "framer-motion";
import SidebarMenu from './SidebarMenu'
import { Outlet } from "react-router-dom";
// The outlet component
const routes = [
{
path: "/user",
name: "Users",
icon: <FaHouseUser />,
},
{
path: "/project",
name: "Project",
icon: <FaTasks />,
},
{
path: "/login",
name: "Logout",
icon: <FaUser />,
},
];
const Private = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
const showAnimation = {
hidden: {
width: 0,
opacity: 0,
transition: {
duration: 0.5,
},
},
show: {
opacity: 1,
width: "auto",
transition: {
duration: 0.5,
},
},
};
return (
<>
<div className="main-container">
<motion.div
animate={{
width: isOpen ? "200px" : "45px",
transition: {
duration: 0.5,
type: "spring",
damping: 10,
},
}}
className={`sidebar `}
>
<div className="top_section">
<AnimatePresence>
{isOpen && (
<motion.h1
variants={showAnimation}
initial="hidden"
animate="show"
exit="hidden"
className="logo"
>
Evalue portal
</motion.h1>
)}
</AnimatePresence>
<div className="bars">
<FaBars onClick={toggle} />
</div>
</div>
<section className="routes">
{routes.map((route, index) => {
if (route.subRoutes) {
return (
<SidebarMenu
setIsOpen={setIsOpen}
route={route}
showAnimation={showAnimation}
isOpen={isOpen}
/>
);
}
return (
<NavLink
to={route.path}
key={index}
className="link"
// activeClassName="active"
>
<div className="icon">{route.icon}</div>
<AnimatePresence>
{isOpen && (
<motion.div
variants={showAnimation}
initial="hidden"
animate="show"
exit="hidden"
className="link_text"
>
{route.name}
</motion.div>
)}
</AnimatePresence>
</NavLink>
);
})}
</section>
</motion.div>
<main>
<Outlet /> // The outlet component
</main>
</div>
</>
);
};
export default Private
Basically the Outlet will render the routes you put inside the /admin route. More info in this link

Related

How can one navigate to previous location on React using react router version 6 when a user logs in? [duplicate]

How to create a protected route with react-router-dom and storing the response in localStorage, so that when a user tries to open next time they can view their details again. After login, they should redirect to the dashboard page.
All functionality is added in ContextApi.
Codesandbox link : Code
I tried but was not able to achieve it
Route Page
import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";
function Routes() {
const { authLogin } = useContext(globalC);
console.log("authLogin", authLogin);
return (
<BrowserRouter>
<Switch>
{authLogin ? (
<>
<Route path="/dashboard" component={Dashboard} exact />
<Route exact path="/About" component={About} />
</>
) : (
<Route path="/" component={Login} exact />
)}
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
);
}
export default Routes;
Context Page
import React, { Component, createContext } from "react";
import axios from "axios";
export const globalC = createContext();
export class Gprov extends Component {
state = {
authLogin: null,
authLoginerror: null
};
componentDidMount() {
var localData = JSON.parse(localStorage.getItem("loginDetail"));
if (localData) {
this.setState({
authLogin: localData
});
}
}
loginData = async () => {
let payload = {
token: "ctz43XoULrgv_0p1pvq7tA",
data: {
name: "nameFirst",
email: "internetEmail",
phone: "phoneHome",
_repeat: 300
}
};
await axios
.post(`https://app.fakejson.com/q`, payload)
.then((res) => {
if (res.status === 200) {
this.setState({
authLogin: res.data
});
localStorage.setItem("loginDetail", JSON.stringify(res.data));
}
})
.catch((err) =>
this.setState({
authLoginerror: err
})
);
};
render() {
// console.log(localStorage.getItem("loginDetail"));
return (
<globalC.Provider
value={{
...this.state,
loginData: this.loginData
}}
>
{this.props.children}
</globalC.Provider>
);
}
}
Issue
<BrowserRouter>
<Switch>
{authLogin ? (
<>
<Route path="/dashboard" component={Dashboard} exact />
<Route exact path="/About" component={About} />
</>
) : (
<Route path="/" component={Login} exact />
)}
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
The Switch doesn't handle rendering anything other than Route and Redirect components. If you want to "nest" like this then you need to wrap each in generic routes, but that is completely unnecessary.
Your login component also doesn't handle redirecting back to any "home" page or private routes that were originally being accessed.
Solution
react-router-dom v5
Create a PrivateRoute component that consumes your auth context.
const PrivateRoute = (props) => {
const location = useLocation();
const { authLogin } = useContext(globalC);
if (authLogin === undefined) {
return null; // or loading indicator/spinner/etc
}
return authLogin ? (
<Route {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>
);
};
Update your Login component to handle redirecting back to the original route being accessed.
export default function Login() {
const location = useLocation();
const history = useHistory();
const { authLogin, loginData } = useContext(globalC);
useEffect(() => {
if (authLogin) {
const { from } = location.state || { from: { pathname: "/" } };
history.replace(from);
}
}, [authLogin, history, location]);
return (
<div
style={{ height: "100vh" }}
className="d-flex justify-content-center align-items-center"
>
<button type="button" onClick={loginData} className="btn btn-primary">
Login
</button>
</div>
);
}
Render all your routes in a "flat list"
function Routes() {
return (
<BrowserRouter>
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<PrivateRoute path="/About" component={About} />
<Route path="/login" component={Login} />
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
);
}
react-router-dom v6
In version 6 custom route components have fallen out of favor, the preferred method is to use an auth layout component.
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRoutes = () => {
const location = useLocation();
const { authLogin } = useContext(globalC);
if (authLogin === undefined) {
return null; // or loading indicator/spinner/etc
}
return authLogin
? <Outlet />
: <Navigate to="/login" replace state={{ from: location }} />;
}
...
<BrowserRouter>
<Routes>
<Route path="/" element={<PrivateRoutes />} >
<Route path="dashboard" element={<Dashboard />} />
<Route path="about" element={<About />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
</BrowserRouter>
or
const routes = [
{
path: "/",
element: <PrivateRoutes />,
children: [
{
path: "dashboard",
element: <Dashboard />,
},
{
path: "about",
element: <About />
},
],
},
{
path: "/login",
element: <Login />,
},
{
path: "*",
element: <PageNotFound />
},
];
...
export default function Login() {
const location = useLocation();
const navigate = useNavigate();
const { authLogin, loginData } = useContext(globalC);
useEffect(() => {
if (authLogin) {
const { from } = location.state || { from: { pathname: "/" } };
navigate(from, { replace: true });
}
}, [authLogin, location, navigate]);
return (
<div
style={{ height: "100vh" }}
className="d-flex justify-content-center align-items-center"
>
<button type="button" onClick={loginData} className="btn btn-primary">
Login
</button>
</div>
);
}
For v6:
import { Routes, Route, Navigate } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/public" element={<PublicPage />} />
<Route
path="/protected"
element={
<RequireAuth redirectTo="/login">
<ProtectedPage />
</RequireAuth>
}
/>
</Routes>
);
}
function RequireAuth({ children, redirectTo }) {
let isAuthenticated = getAuth();
return isAuthenticated ? children : <Navigate to={redirectTo} />;
}
Link to docs:
https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f
import { v4 as uuidv4 } from "uuid";
const routes = [
{
id: uuidv4(),
isProtected: false,
exact: true,
path: "/home",
component: param => <Overview {...param} />,
},
{
id: uuidv4(),
isProtected: true,
exact: true,
path: "/protected",
component: param => <Overview {...param} />,
allowed: [...advanceProducts], // subscription
},
{
// if you conditional based rendering for same path
id: uuidv4(),
isProtected: true,
exact: true,
path: "/",
component: null,
conditionalComponent: true,
allowed: {
[subscription1]: param => <Overview {...param} />,
[subscription2]: param => <Customers {...param} />,
},
},
]
// Navigation Component
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Switch, Route, useLocation } from "react-router-dom";
// ...component logic
<Switch>
{routes.map(params => {
return (
<ProtectedRoutes
exact
routeParams={params}
key={params.path}
path={params.path}
/>
);
})}
<Route
render={() => {
props.setHideNav(true);
setHideHeader(true);
return <ErrorPage type={404} />;
}}
/>
</Switch>
// ProtectedRoute component
import React from "react";
import { Route } from "react-router-dom";
import { useSelector } from "react-redux";
const ProtectedRoutes = props => {
const { routeParams } = props;
const currentSubscription = 'xyz'; // your current subscription;
if (routeParams.conditionalComponent) {
return (
<Route
key={routeParams.path}
path={routeParams.path}
render={routeParams.allowed[currentSubscription]}
/>
);
}
if (routeParams.isProtected && routeParams.allowed.includes(currentSubscription)) {
return (
<Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
);
}
if (!routeParams.isProtected) {
return (
<Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
);
}
return null;
};
export default ProtectedRoutes;
Would like to add highlight never forget to give path as prop to ProtectedRoute, else it will not work.
Here is an easy react-router v6 protected route. I have put all the routes I want to protect in a routes.js:-
const routes = [{ path: "/dasboard", name:"Dashboard", element: <Dashboard/> }]
To render the routes just map them as follows: -
<Routes>
{routes.map((routes, id) => {
return(
<Route
key={id}
path={route.path}
exact={route.exact}
name={route.name}
element={
localStorage.getItem("token") ? (
route.element
) : (
<Navigate to="/login" />
)
}
)
})
}
</Routes>
If you want an easy way to implement then use Login in App.js, if user is loggedin then set user variable. If user variable is set then start those route else it will stuck at login page. I implemented this in my project.
return (
<div>
<Notification notification={notification} type={notificationType} />
{
user === null &&
<LoginForm startLogin={handleLogin} />
}
{
user !== null &&
<NavBar user={user} setUser={setUser} />
}
{
user !== null &&
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route exact path="/adduser" element={<AddUser />} /> />
<Route exact path="/viewuser/:id" element={<ViewUser />} />
</Routes>
</Router>
}
</div>
)

ProtectedRoutes in reactjs cannot be used inside Routes? [duplicate]

How to create a protected route with react-router-dom and storing the response in localStorage, so that when a user tries to open next time they can view their details again. After login, they should redirect to the dashboard page.
All functionality is added in ContextApi.
Codesandbox link : Code
I tried but was not able to achieve it
Route Page
import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";
function Routes() {
const { authLogin } = useContext(globalC);
console.log("authLogin", authLogin);
return (
<BrowserRouter>
<Switch>
{authLogin ? (
<>
<Route path="/dashboard" component={Dashboard} exact />
<Route exact path="/About" component={About} />
</>
) : (
<Route path="/" component={Login} exact />
)}
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
);
}
export default Routes;
Context Page
import React, { Component, createContext } from "react";
import axios from "axios";
export const globalC = createContext();
export class Gprov extends Component {
state = {
authLogin: null,
authLoginerror: null
};
componentDidMount() {
var localData = JSON.parse(localStorage.getItem("loginDetail"));
if (localData) {
this.setState({
authLogin: localData
});
}
}
loginData = async () => {
let payload = {
token: "ctz43XoULrgv_0p1pvq7tA",
data: {
name: "nameFirst",
email: "internetEmail",
phone: "phoneHome",
_repeat: 300
}
};
await axios
.post(`https://app.fakejson.com/q`, payload)
.then((res) => {
if (res.status === 200) {
this.setState({
authLogin: res.data
});
localStorage.setItem("loginDetail", JSON.stringify(res.data));
}
})
.catch((err) =>
this.setState({
authLoginerror: err
})
);
};
render() {
// console.log(localStorage.getItem("loginDetail"));
return (
<globalC.Provider
value={{
...this.state,
loginData: this.loginData
}}
>
{this.props.children}
</globalC.Provider>
);
}
}
Issue
<BrowserRouter>
<Switch>
{authLogin ? (
<>
<Route path="/dashboard" component={Dashboard} exact />
<Route exact path="/About" component={About} />
</>
) : (
<Route path="/" component={Login} exact />
)}
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
The Switch doesn't handle rendering anything other than Route and Redirect components. If you want to "nest" like this then you need to wrap each in generic routes, but that is completely unnecessary.
Your login component also doesn't handle redirecting back to any "home" page or private routes that were originally being accessed.
Solution
react-router-dom v5
Create a PrivateRoute component that consumes your auth context.
const PrivateRoute = (props) => {
const location = useLocation();
const { authLogin } = useContext(globalC);
if (authLogin === undefined) {
return null; // or loading indicator/spinner/etc
}
return authLogin ? (
<Route {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>
);
};
Update your Login component to handle redirecting back to the original route being accessed.
export default function Login() {
const location = useLocation();
const history = useHistory();
const { authLogin, loginData } = useContext(globalC);
useEffect(() => {
if (authLogin) {
const { from } = location.state || { from: { pathname: "/" } };
history.replace(from);
}
}, [authLogin, history, location]);
return (
<div
style={{ height: "100vh" }}
className="d-flex justify-content-center align-items-center"
>
<button type="button" onClick={loginData} className="btn btn-primary">
Login
</button>
</div>
);
}
Render all your routes in a "flat list"
function Routes() {
return (
<BrowserRouter>
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<PrivateRoute path="/About" component={About} />
<Route path="/login" component={Login} />
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
);
}
react-router-dom v6
In version 6 custom route components have fallen out of favor, the preferred method is to use an auth layout component.
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRoutes = () => {
const location = useLocation();
const { authLogin } = useContext(globalC);
if (authLogin === undefined) {
return null; // or loading indicator/spinner/etc
}
return authLogin
? <Outlet />
: <Navigate to="/login" replace state={{ from: location }} />;
}
...
<BrowserRouter>
<Routes>
<Route path="/" element={<PrivateRoutes />} >
<Route path="dashboard" element={<Dashboard />} />
<Route path="about" element={<About />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
</BrowserRouter>
or
const routes = [
{
path: "/",
element: <PrivateRoutes />,
children: [
{
path: "dashboard",
element: <Dashboard />,
},
{
path: "about",
element: <About />
},
],
},
{
path: "/login",
element: <Login />,
},
{
path: "*",
element: <PageNotFound />
},
];
...
export default function Login() {
const location = useLocation();
const navigate = useNavigate();
const { authLogin, loginData } = useContext(globalC);
useEffect(() => {
if (authLogin) {
const { from } = location.state || { from: { pathname: "/" } };
navigate(from, { replace: true });
}
}, [authLogin, location, navigate]);
return (
<div
style={{ height: "100vh" }}
className="d-flex justify-content-center align-items-center"
>
<button type="button" onClick={loginData} className="btn btn-primary">
Login
</button>
</div>
);
}
For v6:
import { Routes, Route, Navigate } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/public" element={<PublicPage />} />
<Route
path="/protected"
element={
<RequireAuth redirectTo="/login">
<ProtectedPage />
</RequireAuth>
}
/>
</Routes>
);
}
function RequireAuth({ children, redirectTo }) {
let isAuthenticated = getAuth();
return isAuthenticated ? children : <Navigate to={redirectTo} />;
}
Link to docs:
https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f
import { v4 as uuidv4 } from "uuid";
const routes = [
{
id: uuidv4(),
isProtected: false,
exact: true,
path: "/home",
component: param => <Overview {...param} />,
},
{
id: uuidv4(),
isProtected: true,
exact: true,
path: "/protected",
component: param => <Overview {...param} />,
allowed: [...advanceProducts], // subscription
},
{
// if you conditional based rendering for same path
id: uuidv4(),
isProtected: true,
exact: true,
path: "/",
component: null,
conditionalComponent: true,
allowed: {
[subscription1]: param => <Overview {...param} />,
[subscription2]: param => <Customers {...param} />,
},
},
]
// Navigation Component
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Switch, Route, useLocation } from "react-router-dom";
// ...component logic
<Switch>
{routes.map(params => {
return (
<ProtectedRoutes
exact
routeParams={params}
key={params.path}
path={params.path}
/>
);
})}
<Route
render={() => {
props.setHideNav(true);
setHideHeader(true);
return <ErrorPage type={404} />;
}}
/>
</Switch>
// ProtectedRoute component
import React from "react";
import { Route } from "react-router-dom";
import { useSelector } from "react-redux";
const ProtectedRoutes = props => {
const { routeParams } = props;
const currentSubscription = 'xyz'; // your current subscription;
if (routeParams.conditionalComponent) {
return (
<Route
key={routeParams.path}
path={routeParams.path}
render={routeParams.allowed[currentSubscription]}
/>
);
}
if (routeParams.isProtected && routeParams.allowed.includes(currentSubscription)) {
return (
<Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
);
}
if (!routeParams.isProtected) {
return (
<Route key={routeParams.path} path={routeParams.path} render={routeParams?.component} />
);
}
return null;
};
export default ProtectedRoutes;
Would like to add highlight never forget to give path as prop to ProtectedRoute, else it will not work.
Here is an easy react-router v6 protected route. I have put all the routes I want to protect in a routes.js:-
const routes = [{ path: "/dasboard", name:"Dashboard", element: <Dashboard/> }]
To render the routes just map them as follows: -
<Routes>
{routes.map((routes, id) => {
return(
<Route
key={id}
path={route.path}
exact={route.exact}
name={route.name}
element={
localStorage.getItem("token") ? (
route.element
) : (
<Navigate to="/login" />
)
}
)
})
}
</Routes>
If you want an easy way to implement then use Login in App.js, if user is loggedin then set user variable. If user variable is set then start those route else it will stuck at login page. I implemented this in my project.
return (
<div>
<Notification notification={notification} type={notificationType} />
{
user === null &&
<LoginForm startLogin={handleLogin} />
}
{
user !== null &&
<NavBar user={user} setUser={setUser} />
}
{
user !== null &&
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route exact path="/adduser" element={<AddUser />} /> />
<Route exact path="/viewuser/:id" element={<ViewUser />} />
</Routes>
</Router>
}
</div>
)

Why don't Framer Motion pages load after using the menu?

I'm using framer-motion with react to make transitions between my pages, but I have an issue with one transition.
When I'm in the homepage, scroll a bit and click on the menu to go to other page, the next page is empty. In fact by looking in the inspector I can see that the previous page (home) is still in the DOM (+ the new one) and did not exit.
video of the bug : https://www.awesomescreenshot.com/video/11523168
Here's my home component :
import React, {useState, useEffect, useContext} from 'react'
import FirstSection from './FirstSection/FirstSection';
import StickyNav from './FirstSection/StickyNav/StickyNav';
import SndSection from "../sections/Content2/SndSection.js"
import './Home.css';
import LeftOne from "../sections/FirstSection/LeftOne.js";
import ThirdSection from './Content3/ThirdSection';
import { slideContext } from '../../App';
import { motion } from 'framer-motion';
export default function Home() {
const context = useContext(slideContext);
const [scroll, setScroll] = useState();
useEffect(() => {
const handleScroll = event => {
setScroll(window.scrollY);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
<motion.div
id={context.end ? "end-transition" : ""}
className='home'
initial={{width:0, opacity:0}}
animate={{width:'100%', opacity:1}}
exit={{x:window.innerWidth, transition:{duration: 0.3}, opacity:0}}
>
{scroll >= 100 ? <StickyNav /> : ""}
<div id="page">
<LeftOne element='v1'/>
<div id="ctn">
<FirstSection />
<SndSection />
<ThirdSection />
</div>
</div>
</motion.div>
)
}
App.js :
return (
<HashRouter>
<slideContext.Provider value={{end, setEnd, endInscr, setEndInscr, number, setNumber}}>
<div className="App">
<AnimatedRoutes />
</div>
</slideContext.Provider>
</HashRouter>
);
AnimatedRoutes :
import React from 'react'
import {Routes, Route, useLocation} from "react-router-dom";
import AboutUs from './AboutUs/AboutUs';
import Error from './Error';
import Inscription from './Inscription/Inscription';
import Thanks from './Inscription/Thanks';
import Privacy from './Privacy/Privacy';
import Home from './sections/Home';
import Terms from './Terms&Conditions/Terms';
import {AnimatePresence} from 'framer-motion';
export default function AnimatedRoutes() {
const location = useLocation();
return (
<AnimatePresence>
<Routes location={location} key={location.pathname}>
<Route path='/' element={<Home />} />
<Route path='/register' element = {<Inscription />} />
<Route path='/thanks-registration' element ={<Thanks />} />
<Route path='/aboutUs' element={<AboutUs />}/>
<Route path='/termsAndConditions' element={<Terms />} />
<Route path="/privacy" element={<Privacy />}/>
<Route path="/error" element={<Error />} />
</Routes>
</AnimatePresence>
)
}

Pagination in react not working. Adds in extra to the URL string once loaded

hi hope someone can help me. I have added pagination into my react app. I have checked and the query strings are working as they should be on the back end. However when I try and click through the pagination buttons it adds extra to the URL so instead of localhost:3000/topic/page/1 it is localhost:3000/topic/page/topic/page/1. Therefore I get a not found error when I click on the link.
Routes file
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import Register from '../auth/Register';
import Login from '../auth/Login';
import Alert from '../layout/Alert';
import Dashboard from '../dashboard/Dashboard';
import CreateProfile from '../profile-forms/CreateProfile';
import EditProfile from '../profile-forms/EditProfile';
import Profiles from '../profiles/Profiles';
import Profile from '../profile/Profile';
import Posts from '../posts/Posts';
import Post from '../post/Post';
import Topics from '../topic/Topics';
import Flashcard from '../flashcard/Flashcard';
import Quiz from '../quiz/Quiz';
import Factsheet from '../factsheet/Factsheet';
import NotFound from '../layout/NotFound';
import PrivateRoute from '../routing/PrivateRoute';
const Routes = () => {
return (
<section className="container">
<Alert />
<Switch>
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<PrivateRoute exact path="/profiles" component={Profiles} />
<PrivateRoute exact path="/profile/:id" component={Profile} />
<PrivateRoute exact path="/dashboard" component={Dashboard} />
<PrivateRoute exact path='/create-profile' component={CreateProfile} />
<PrivateRoute exact path='/edit-profile' component={EditProfile} />
<PrivateRoute exact path='/topic' component={Topics} />
<PrivateRoute exact path='/topic/search/:keyword' component={Topics} />
<PrivateRoute exact path='/topic/page/:pageNumber' component={Topics} />
<PrivateRoute exact path='/topic/search/:keyword/page/:pageNumber' component={Topics} />
<PrivateRoute exact path='/topic/flashcard/:id' component={Flashcard} />
<PrivateRoute exact path='/topic/quiz/:id' component={Quiz} />
<PrivateRoute exact path='/topic/factsheet/:id' component={Factsheet} />
<PrivateRoute exact path="/posts" component={Posts} />
<PrivateRoute exact path="/posts/:id" component={Post} />
<Route component={NotFound} />
</Switch>
</section>
);
};
export default Routes;
Paginate.js
import React from 'react'
import { Pagination } from 'react-bootstrap'
import { Link } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap'
const Paginate = ({ pages, page, keyword = '' }) => {
return (
pages > 1 && (
<Pagination>
{[...Array(pages).keys()].map((x) => (
<LinkContainer
tag={Link}
key={x + 1}
to={keyword
? `topic/search/${keyword}/page/${x + 1}`
: `topic/page/${x + 1}`
}
>
<Pagination.Item active={x + 1 === page}>{x + 1}</Pagination.Item>
</LinkContainer>
))}
</Pagination>
)
)
}
export default Paginate
SearchBox.js
import React, { useState } from 'react'
import { Form, Button } from 'react-bootstrap'
const SearchBox = ({ history }) => {
const [keyword, setKeyword] = useState('')
const submitHandler = (e) => {
e.preventDefault()
if(keyword.trim()) {
history.push(`/topic/search/${keyword}`)
} else {
history.push('/topic')
}
}
return (
<Form onSubmit={submitHandler} inline>
<Form.Control
type="text"
name="q"
onChange={(e) => setKeyword(e.target.value)}
placeholder="Search Topics....."
></Form.Control>
</Form>
)
}
export default SearchBox
topic.js
import React, { Fragment, useEffect } from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Spinner from '../layout/Spinner';
import Paginate from '../layout/Paginate'
import TopicItem from './TopicItem';
import { getTopics } from '../../actions/topic';
const Topics = ({ getTopics, topic: { topics, loading, pages, page }, match }) => {
const keyword = match.params.keyword
const pageNumber = match.params.pageNumber || 1
useEffect(() => {
getTopics(keyword, pageNumber);
}, [getTopics, keyword, pageNumber])
return (
<Fragment>
{loading ? (
<Spinner />
) : (
<Fragment>
<h1 className="large text-primary1 my-2">Pick a Topic</h1>
<Link to="/topic" className="btn my-4">
Back To Topics
</Link>
<div className="card-grid-home">
{topics.length > 0 ? (
topics.map(topic => (
<TopicItem key={topic._id} topic={topic} />
))
) : (
<h4>No topics found......</h4>
)}
</div>
<Paginate pages={pages} page={page} keyword={keyword ? keyword : ''}/>
</Fragment>
)}
</Fragment>
)
};
Topics.prototype = {
getTopics: PropTypes.func.isRequired,
topic: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
topic: state.topic
})
export default connect(mapStateToProps, { getTopics })(Topics)
Thanks in advance
Realised that I was missing a / for the start of the routes. Silly mistake.

ReactJS Error: Element type is invalid: expected a string (for built-in components)

I am trying to export class and import it in another file, but I kept getting this error: ...
Check the render method of NewsfeedDetail.
I want to export component from this file: NewsfeedDetail.js
import React from "react";
import {
Card,
Container,
Dimmer,
Header,
Image,
Loader,
Message,
Segment,
} from "semantic-ui-react";
import { articleDetailURL, } from "../constants";
import axios from "axios";
class NewsfeedDetail extends React.Component {
state = {
loading: false,
error: null,
data: [],
};
componentDidMount() {
this.handleFetchItem();
};
handleFetchItem = () => {
const {
match: { params }
} = this.props;
this.setState({ loading: true });
axios
.get(articleDetailURL(params.articleID))
.then(res => {
this.setState({ data: res.data, loading: false });
})
.catch(err => {
this.setState({ error: err, loading: false });
});
};
render() {
const { data, error, loading } = this.state;
const item = data;
return (
<Container>
{error && (
<Message
error
header="There was some errors with your submission"
content={JSON.stringify(error)}
/>
)}
{loading && (
<Segment>
<Dimmer active inverted>
<Loader inverted>Loading</Loader>
</Dimmer>
<Image src="/images/wireframe/short-paragraph.png" />
</Segment>
)}
<Header as='h4' textAlign='center'>
<Header.Content>
{item.title}
</Header.Content>
</Header>
<Card>
<Card.Content>
<Card.Category >
{item.category}
</Card.Category>
<Card.Description>
{item.description}
</Card.Description>
<Card.Body>
{item.body}
</Card.Body>
</Card.Content>
</Card>
</Container>
);
}
};
export default NewsfeedDetail;
And I want to import it in this file: routes.js
import React from "react";
import { Route } from "react-router-dom";
import Hoc from "./hoc/hoc";
import Login from "./containers/Login";
import Signup from "./containers/Signup";
import HomepageLayout from "./containers/Home";
import ProductList from "./containers/ProductList";
import ProductDetail from "./containers/ProductDetail";
import OrderSummary from "./containers/OrderSummary";
import Checkout from "./containers/Checkout";
import Profile from "./containers/Profile";
import AboutLayout from "./containers/About";
import HotelLayout from "./containers/Hotel";
import NewsfeedList from "./containers/NewsfeedList";
import NewsfeedDetail from "./containers/NewsfeedDetail";
const BaseRouter = () => (
<Hoc>
<Route exact path="/products" component={ProductList} />
<Route path="/products/:productID" component={ProductDetail} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
<Route path="/order-summary" component={OrderSummary} />
<Route path="/checkout" component={Checkout} />
<Route path="/profile" component={Profile} />
<Route exact path="/" component={HomepageLayout} />
<Route exact path="/about" component={AboutLayout} />
<Route exact path="/hotel" component={HotelLayout} />
<Route exact path="/articles" component={NewsfeedList} />
<Route path="/articles/:articleID" component={NewsfeedDetail} />
</Hoc>
);
export default BaseRouter;
I have tried exporting with no default, and use {} when importing but it does not work either.
Please help me.

Categories