My old method:
<Route
key={i}
path={path}
render={(props) => {
if (!localStorage.getItem("token")) {
<Redirect
to={{ pathname: "/login", state: { from: props.location } }}
/>
}
return (
<AuthLayout>
<Component {...props} />
</AuthLayout>
);
}}
/>
Replacing render
with the new element
gives me:
Functions are not valid as a React child. This may happen if you return a Component instead of from render
Apparently the new API simply expects:
<Route
key={i}
path={path}
element={
<Component />
}
/>
What I'm really trying to accomplish is to dynamically render the component as such:
{authProtectedRoutes.map(({ path, Component }, i) => {
<Route
key={i}
path={path}
element={
// If no auth token, redirect to login
if (!token) {
<Navigate to="/login" />
} else {
<AuthLayout>
<Component />
</AuthLayout>
}
}
/>
})}
Not sure how to do this ...
EDIT:
My array of components is as such:
const authProtectedRoutes = [
{ path: "/dashboard", Component: Dashboard },
{ path: "/pages-starter", Component: StarterPage },
When I try to return Component
in my loop I get:
React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
CodePudding user response:
element={
// If no auth token, redirect to login
if (!token) {
<Navigate to="/login" />
} else {
<AuthLayout>
<Component />
</AuthLayout>
}
}
You can't do an if
in the middle of jsx, but you can do a conditional operator:
element={!token ? (
<Navigate to="/login" />
) : (
<AuthLayout>
<Component />
</AuthLayout>
)}
CodePudding user response:
The element
prop expects a ReactNode
(a.k.a. JSX) and not javascript (i.e. the if-statement).
Since it seems you render your authenticated routes in bulk a more optimal solution would be to wrap them all in a single AuthLayout
component that checks the token. Instead of rendering the children
prop it renders an Outlet
for nested routes to be rendered into.
Example:
const AuthLayout = ({ token }) => {
// ... existing AuthLayout logic
return token
? (
<div /* awesome auth layout CSS style */>
...
<Outlet /> // <-- nested routes render here
</div>
)
: <Navigate to="/login" />;
};
Don't forget to return the Route
from the map callback.
<Route element={<AuthLayout token={token} />}>
{authProtectedRoutes.map(({ path, Component }) => (
<Route key={path} path={path} element={<Component />} />
))}
</Route>