I currently use react-router-dom to separate routing for authenticated/non-authenticated people. But Element has an error for missing the properties.
How can withoutAuth() work for authentication routes?
Type '() => Element' is missing the following properties from type 'ReactElement<any, string | JSXElementConstructor>': type, props, key
function App() {
return (
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/" element={withoutAuth(<Signup />)} />
</Routes>
</AuthProvider>
</BrowserRouter>
);
}
const withoutAuth = (Element: ElementType) =>
function WithoutAuth() {
const { currentFBUser } = useAuthContext()
if (currentFBUser) {
return <Navigate to="/dashboard" />
}
return <Element />
}
You don't generally pass JSX literals to Higher Order Components, and the element prop takes a JSX literal instead of a reference to a React component.
// (1) Create a new decorated component
const SignUpWithoutAuth = withoutAuth(Signup);
function App() {
return (
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
// (2) Pass the new decorated component as JSX to `element` prop
<Route path="/" element={<SignUpWithoutAuth />} />
</Routes>
</AuthProvider>
</BrowserRouter>
);
}
This being said, it would be more conventional to implement as a wrapper component than a HOC in RRDv6.
Example:
function WithoutAuth({ children }) {
const { currentFBUser } = useAuthContext()
if (currentFBUser) {
return <Navigate to="/dashboard" />
}
return children;
}
function App() {
return (
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route
path="/"
element={(
<WithoutAuth>
<Signup />
</WithoutAuth>
)}
/>
</Routes>
</AuthProvider>
</BrowserRouter>
);
}
Either should work.
Related
Can anyone tell me what's wrong in this code ??
I am protecting the route but the error is comming .
I have creted a ProtectionRoute component which calls AUTH_FUNC(Checks whether user is locked in or not) from the TwitterState.js and if the user is logged in then the ProtectionRoute returns the Component and else redirect to the login page !
App.js
import {BrowserRouter as Router , Routes , Route , useNavigate} from "react-router-dom"
import Home from "./pages/Home"
import Auth from "./pages/Auth"
import Profile from "./pages/Profile"
import Bookmark from "./pages/Bookmark"
import NotFound from "./pages/NotFound"
import Explore from "./pages/Explore"
import TrendingTags from "./pages/TrendingTags"
import Discover from "./pages/Discover"
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import Register from "./pages/Register"
import EditProfile from "./pages/EditProfile"
import ProtectedRoute from "./components/ProtectedRoute"
function App() {
return (
<Router>
<ToastContainer />
<Routes>
<Route path="/" element={<ProtectedRoute><Home/></ProtectedRoute>}/>
<Route path="/auth" element={<ProtectedRoute><Auth/></ProtectedRoute>}/>
<Route path="/profile" element={<ProtectedRoute><Profile/></ProtectedRoute>} />
<Route path="/message" element={<ProtectedRoute><NotFound/></ProtectedRoute>} />
<Route path="/notifications" element={<ProtectedRoute><NotFound/></ProtectedRoute>} />
<Route path="/bookmark" element={<ProtectedRoute><Bookmark/></ProtectedRoute>} />
<Route path="/explore" element={<ProtectedRoute><Explore/></ProtectedRoute>} />
<Route path="/explore/trending/:tagName" element={<ProtectedRoute><TrendingTags/></ProtectedRoute>} />
<Route path="/discover" element={<ProtectedRoute><Discover/></ProtectedRoute>} />
<Route path="/register" element={<ProtectedRoute><Register /></ProtectedRoute>} />
<Route path="/profile/edit" element={<ProtectedRoute><EditProfile /></ProtectedRoute>} />
</Routes>
</Router>
);
}
export default App;
ProtectedRoute.js
import React , {useContext} from "react";
import { Route, Navigate } from "react-router-dom";
import TwitterContext from "../context/TwitterContext";
export default function ProtectedRoute ({children}) {
const {AUTH_FUNC} = useContext(TwitterContext)
const loggedin = AUTH_FUNC()
if(!loggedin){
return <Navigate to="/auth"/>
}
return children
};
Twitter.jsx
import TwitterContext from "./TwitterContext";
const TwitterState = (props) => {
const AUTH_FUNC = () =>{
const res = JSON.parse(localStorage.getItem("UserData"))
if(res !== null){
return true
}
return false
}
return <TwitterContext.Provider value={{AUTH_FUNC}}>
{props.children}
</TwitterContext.Provider>
}
export default TwitterState
Error :
Issue
You are protecting the "/auth" route as well, which when a user is not authenticated yet will create a navigation loop from "/auth" to "/auth", repeat ad nauseam.
function App() {
return (
<Router>
<ToastContainer />
<Routes>
...
<Route path="/auth" element={<ProtectedRoute><Auth/></ProtectedRoute>}/>
...
</Routes>
</Router>
);
}
export default function ProtectedRoute ({ children }) {
const { AUTH_FUNC } = useContext(TwitterContext);
const loggedin = AUTH_FUNC();
if (!loggedin) {
return <Navigate to="/auth"/>;
}
return children;
};
Solution
You don't want to protect the authentication route the same way as the routes that require authentication. Remove ProtectedRoute from the "/auth" route.
Refactor the ProtectedRoute to render an Outlet also so you can make the code more DRY. This allows the ProtectedRoute component to wrap entire sets of routes that need to be protected.
import { Navigate, Outlet } from 'react-router-dom';
export default function ProtectedRoute () {
const { AUTH_FUNC } = useContext(TwitterContext);
const loggedin = AUTH_FUNC();
if (loggedin === undefined) {
return null; // or loading indicator/spinner/etc
}
return loggedin
? <Outlet />
: <Navigate to="/auth" replace />;
};
function App() {
return (
<Router>
<ToastContainer />
<Routes>
{/* Unprotected routes */}
<Route path="/auth" element={<Auth />} />
<Route path="/register" element={<Register />} />
{/* Protected routes */}
<Route element={<ProtectedRoute />}>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/message" element={<NotFound />} />
<Route path="/notifications" element={<NotFound />} />
<Route path="/bookmark" element={<Bookmark />} />
<Route path="/explore" element={<Explore />} />
<Route path="/explore/trending/:tagName" element={<TrendingTags />} />
<Route path="/discover" element={<Discover />} />
<Route path="/profile/edit" element={<EditProfile />} />
</Route>
</Routes>
</Router>
);
}
It's also a common pattern to protect the "anonymous" routes from authenticated users. For this create another protected route component that does the inverse of the ProtectedRoute component.
import { Navigate, Outlet } from 'react-router-dom';
export default function AnonymousRoute () {
const { AUTH_FUNC } = useContext(TwitterContext);
const loggedin = AUTH_FUNC();
if (loggedin === undefined) {
return null; // or loading indicator/spinner/etc
}
return loggedin
? <Navigate to="/" replace />
: <Outlet />;
};
function App() {
return (
<Router>
<ToastContainer />
<Routes>
{/* Anonymous routes */}
<Route element={<AnonymousRoute />}>
<Route path="/auth" element={<Auth />} />
<Route path="/register" element={<Register />} />
</Route>
{/* Protected routes */}
<Route element={<ProtectedRoute />}>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/message" element={<NotFound />} />
<Route path="/notifications" element={<NotFound />} />
<Route path="/bookmark" element={<Bookmark />} />
<Route path="/explore" element={<Explore />} />
<Route path="/explore/trending/:tagName" element={<TrendingTags />} />
<Route path="/discover" element={<Discover />} />
<Route path="/profile/edit" element={<EditProfile />} />
</Route>
</Routes>
</Router>
);
}
The Auth is in protected route and causes the navigation loop.
<Route path="/auth" element={<ProtectedRoute><Auth/></ProtectedRoute>}/>
export default function ProtectedRoute ({children}) {
const {AUTH_FUNC} = useContext(TwitterContext)
const loggedin = AUTH_FUNC()
if(!loggedin){
return <Navigate to="/auth"/>
}
return children
};
/auth route probably shouldn't be a protected route, in order to function normally.
I am using react-router-dom v6, "react": "^18.2.0", and not able to render a Details component. This is my routing:
function Routing() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<List />} />
<Route path="details/:id" element={<Details />} />
<Route path="other" element={<Other />} />
</Routes>
</BrowserRouter>
);
}
I am using this to try to access the Details component:
<Link to={'details' + `/${props.id}`}/>
The details component is as basic as this:
import react from 'React'
const Details = () => {
return (<h1>HELLO</h1>)
}
export default Details;
But the component will not render, and I am getting the warning "No routes matched location "/details/weI4qFO9/UW9v5WFllYhFw==""
It's only dynamic routing that will not render the component. Any idea what I am doing wrong or missing?
you are missing the / before details on the router and the link
function Routing() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<List />} />
<Route path="/details/:id" element={<Details />} />
<Route path="/other" element={<Other />} />
</Routes>
</BrowserRouter>
);
}
<Link to={`/details/${props.id}`}/>
I don't understand why this code is not working. "isAuthenticated" is a boolean from the moralis API. If it is true it should render outlet and if it's false should render the navigate option.
const ProtectedRoutes = () => {
const { isAuthenticated } = useMoralis();
return isAuthenticated ? <Outlet /> : <Navigate to="/" />;
};
return (
<Routes>
<Route path={ROUTER_PATHS.SIGNUP} element={<Signup />} />
<Route element={<ProtectedRoutes />}>
<Route path={ROUTER_PATHS.EMPLOYER} element={<MarketPlaceEmployer />} />
<Route path={ROUTER_PATHS.EMPLOYEE} element={<MarketPlaceEmployee />} />
</Route>
</Routes>
);
Using <Outlet /> component will make ProtectedRoutes component as Layout component to make ProtectedRoutes work as wrapping component as well you should optionally render children, change ProtectedRoutes component as,
const ProtectedRoutes = ({ children }) => {
const { isAuthenticated } = useMoralis();
if (!isAuthenticated) {
return <Navigate to="/" />;
}
return children ? children : <Outlet />;
};
Also, add exact before path,
return (
<Routes>
<Route path={ROUTER_PATHS.SIGNUP} element={<Signup />} />
<Route element={<ProtectedRoutes />}>
<Route exact path={ROUTER_PATHS.EMPLOYER} element={<MarketPlaceEmployer />} />
<Route exact path={ROUTER_PATHS.EMPLOYEE} element={<MarketPlaceEmployee />} />
</Route>
</Routes>
This question already has answers here:
how could I fix this mistake of routes in react
(2 answers)
Closed 11 months ago.
Matched leaf route at location "/" does not have an element. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.
//App.js File
import {Route, Routes} from 'react-router-dom';
import ProductList from './ProductList';
const App = () => {
return (
<Router >
<Routes>
<Route
exact
path="/"
render=
{ props =>
{
<ProductList {...props}
products={this.state.products}
currentCategory={this.state.currentCategory}
addToCart={this.addToCart} info={productInfo}/>
} }/>
</Routes>
</Router>
)
}
export default App;
When I start adding a route to the program it gives this error, I think the problem is in the render method.
Using a React router
It was fixed by deleting the render and editing it like this.
<Route
exact
path="/"
element={< ProductList products = {
this.state.products
}
currentCategory = {
this.state.currentCategory
}
addToCart = {
this.addToCart
}
info = {
productInfo
} />}/>
Your render method is not returning any value. To return a value from an arrow function use () or return or simply omit the {}.
With ()
<Route
exact
path="/"
render=
{ props =>
{
(<ProductList {...props}
products={this.state.products}
currentCategory={this.state.currentCategory}
addToCart={this.addToCart} info={productInfo} />)
}
}
/>
With return
<Route
exact
path="/"
render=
{ props =>
{
return <ProductList {...props}
products={this.state.products}
currentCategory={this.state.currentCategory}
addToCart={this.addToCart} info={productInfo} />
}
}
/>
Without {}:
<Route
exact
path="/"
render=
{ props =>
<ProductList {...props}
products={this.state.products}
currentCategory={this.state.currentCategory}
addToCart={this.addToCart} info={productInfo} />
}
/>
I am trying to use react-router with props id but it gave me this info:
Matched leaf route at location "/some-12" does not have an element. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.
I'm using "react-router-dom": "6" and "react": "^17.0.2"
//example Routes
import {Route, Routes } from "react-router-dom";
function App()
return(
<>
<Routes>
<Route path="/about" element={<About />}/>
<Route exec={true} path="/something" element={<Something/>}/>
<Route exact={true} path="/something-:id"
render={(props) => {
<Some id={props.match.params.id} />;}}
/>
<Route path="/contact" element={<Contact />}/>
</Routes>
</>```
//example Some
export default function Some({ id }) {
return(
<>
<p>Some with id: {id}
</>
)}
Where I did mistakes?
In react-router-dom version 6 the Route components render all the routed components on the element prop and there are no longer any route props, i.e. no history, location, or match.
Render the Some component on the element prop and use the useParams hook to access the id route match param. If path="/something-:id" doesn't work then try making the id its own path segment, i.e. path="/something/:id".
function App()
return(
<>
<Routes>
<Route path="/about" element={<About />}/>
<Route path="/something" element={<Something/>}/>
<Route path="/something-:id" element={<Some />} />
<Route path="/contact" element={<Contact />}/>
</Routes>
</>
);
}
...
import { useParams } from 'react-router-dom';
export default function Some() {
const { id } = useParams();
return(
<>
<p>Some with id: {id}
</>
);
}
It might be that you missed a return statement in your element prop.
<Route exact={true} path="/something-:id"
render={(props) => {
return <Some id={props.match.params.id} />;}}
/>
// or
<Route exact={true} path="/something-:id"
render={(props) => <Some id={props.match.params.id} />;}/>
Note: Upon further research, the render prop has been removed in v6. You should use element instead and fetch the :id as per Drew Reese's answer