Why components cannot be rendered by custom protected react-routers? - javascript

I have several components to protect authentication. Then I made a new component called ProtectedRoute. In this ProtectedRoute function I only catch properties that are thrown, but somehow I only get the state from React-Context, and the props I send are unreadable, when in console.log() it is undefined.
ProtectedRoute.js:
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
import { withAuth } from './Context/AuthContext'
function ProtectedRoute(props) {
const {component: Component, ...rest} = props
console.log(Component)
return(
props.isLoggedIn ? <Route {...rest} component={Component} /> : <Redirect push to="/" />
)
}
export default withAuth(ProtectedRoute)
App.js:
render() {
return (
<BrowserRouter>
<AuthContextProvider>
<Switch>
<Route exact path="/" component={Login} />
<ProtectedRoute path="/portal" component={Main} />
</Switch>
</AuthContextProvider>
</BrowserRouter>
)
}
I have imported all required component btw, but if I change ProtectedRoute to normal <Route> by react-router, it can render component Main.
Is there something wrong with my code?

Related

Why unable to use protectRoute inside Router in react?

I have a react application in which users can access the homepage only after login/signup.
I have used protectRoutes to implement this , however I m getting the following error inside Router component:
A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
The code for app.js file:
import {useState} from 'react'
import './App.css';
import {Routes,Route,Link} from 'react-router-dom'
import SignupPage from './Pages/SignupPage';
import LoginPage from './Pages/LoginPage';
import Homepage from './Pages/Homepage';
import PrivateRoute from "./Pages/PrivateRoute";
import {HashRouter as Router} from 'react-router-dom'
function App() {
const [username,setUsername]=useState("");
const [currentUser,setCurrentUser]=useState({});
return (
<Router>
<div className="App">
<Route path="/" exact element={<SignupPage></SignupPage>}/>
<Route path="/signup" exact element={<SignupPage currentuser={currentUser} setcurrentuser={setCurrentUser} setusername={setUsername}></SignupPage>}/>
<Route path="/login" exact element={<LoginPage></LoginPage>}/>
<PrivateRoute path="/homepage" exact currentuser={currentUser} element={<Homepage user={currentUser} username={username} setusername={setUsername}></Homepage>}/>
</div>
</Router>
);
}
export default App;
Whats the error here and how do I fix it?
Issue
You are rendering Route components directly and are not wrapping them in a Routes component.
Solution
Refactor the PrivateRoute component to render an Outlet component instead of a Route and wrap the routes you want to protect.
Example:
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRoute = ({ currentuser }) => {
// auth business logic
return isAuthenticated
? <Outlet />
: <Navigate to="/login" replace />;
};
...
import { HashRouter as Router, Routes, Route, Link} from 'react-router-dom'
function App() {
const [username,setUsername]=useState("");
const [currentUser,setCurrentUser]=useState({});
return (
<Router>
<div className="App">
<Routes>
... unprotected routes ...
<Route path="/" element={<SignupPage />} />
<Route
path="/signup"
element={(
<SignupPage
currentuser={currentUser}
setcurrentuser={setCurrentUser}
setusername={setUsername}
/>
)}
/>
<Route path="/login" element={<LoginPage />} />
...
<Route element={<PrivateRoute currentuser={currentUser} />}>
... protected routes ...
<Route
path="/homepage"
element={(
<Homepage
user={currentUser}
username={username}
setusername={setUsername}
/>
)}
/>
...
</Route>
</Routes>
</div>
</Router>
);
}

why Passing Props in Private Route in ReactJs not working properly

Here is mycode of the file PrivateRoute.js
import React from "react";
import {Route,Redirect} from "react-router-dom"
import {isAuthenticated} from "./index"
const PrivateRoutes = (props)=>{
return(
isAuthenticated()?(<Route
render={ (props) =>
<component {...props}/>} />):
(<Redirect to={{ pathname:"/signin"}}/>)
// <h1>hey there</h1>
)
}
export default PrivateRoutes;
In this code it is saying that value of props is read but never used but iam using it in render function,destructuring is also not working here.
Here isAuthenticated() is my boolean function . If it evaluates to true i want to get on more route to user dashboard.
This is how my routes.js file looks like
import React from 'react'
import {BrowserRouter,Route,Switch} from "react-router-dom";
import AdminRoutes from './auth/helper/AdminRoutes';
import PrivateRoutes from './auth/helper/PrivateRoutes';
import Home from './core/Home';
import AdminDashboard from './user/AdminDashBoard';
import Signin from './user/Signin';
import Signup from './user/Signup';
import UserDashboard from './user/UserDashBoard';
function Routes() {
return (
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path="/signup" component={Signup} />
<Route exact path="/signin" component={Signin} />
<PrivateRoutes component="UserDashboard" exact path="/user/dashboard"/>
<AdminRoutes exact path="/admin/dashboard" component={AdminDashboard}/>
</Switch>
</BrowserRouter>
)
}
export default Routes
Help me to solve this problem.
This is because you have declared *two functions, each taking a props object argument, but only the inner/nested function's props is referenced.
Rename the nested props to something else like routeProps and spread both to the rendered component. Remember also that valid React component names are PascalCased.
Example:
const PrivateRoutes = ({ component: Component, ...props }) => {
return isAuthenticated()
? (
<Route
render={(routeProps) => (
<Component {...props} {...routeProps} />
)}
/>
) : <Redirect to={{ pathname:"/signin"}}/>;
}
Then also fix the PrivateRoutes component use to pass a value React component reference instead of a string.
<Switch>
<Route path="/signup" component={Signup} />
<Route path="/signin" component={Signin} />
<PrivateRoutes component={UserDashboard} path="/user/dashboard" />
<AdminRoutes path="/admin/dashboard" component={AdminDashboard} />
<Route path='/' component={Home} />
</Switch>

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

Cannot pass down history prop to Component

I want to pass down the history prop down from the App to the Navigation component.
When I try to do so, I get the following error message:
Failed prop type: The prop history is marked as required in Navigation, but its value is undefined.
How can I resolve this issue?
App.js:
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
const App = props => (
<Router>
<MainLayout {...props}>
<Switch>
<Route exact name="index" path="/" component={Index}/>
<Route component={NotFound}/>
</Switch>
</MainLayout>
</Router>
);
MainLayout.js:
import React from "react";
import PropTypes from "prop-types";
import Navigation from "../../components/Navigation/Navigation";
const MainLayout = props => {
const { children, authenticated, history } = props;
return (
<div>
<Navigation authenticated={authenticated} history={history} />
{children}
</div>
);
};
MainLayout.PropTypes = {
children: PropTypes.node.isRequired,
authenticated: PropTypes.bool.isRequired,
history: PropTypes.object.isRequired,
};
export default MainLayout;
SOLUTION #1:
If you simply convert <MainLayout /> to a <Route /> that renders you will have access to the history object.
<Route render={(props) =>
<MainLayout {...props}>
<Switch>
<Route exact name="index" path="/" component={Index}/>
<Route component={NotFound}/>
</Switch>
</MainLayout>
}/>
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Route.js
<App /> does not have access to history as a prop so this will never do what you are wanting <MainLayout {...props}>
SOLUTION #2
You can also reference the history object as a single exported module in your app and refer to that both React router and any other compopent / javascript file in your app.
import { Router, Switch, Route } from 'react-router-dom';
import history from './history';
const App = props => (
<Router history={history}>
<MainLayout history={history} {...props}>
<Switch>
<Route exact name="index" path="/" component={Index}/>
<Route component={NotFound}/>
</Switch>
</MainLayout>
</Router>
);
(history.js)
import createBrowserHistory from 'history/createBrowserHistory';
export default createBrowserHistory();
https://www.npmjs.com/package/history
For react-router-dom v4
In order to get Router component's prop I used the withRouter, I guess the below change should work,
export default wihtRouter(MainLayout);
This should enable the usage of props.history in MainLayout

Categories

Resources