S
SolidJS9mo ago
kaxa

Can't find replace attribute on <Navigate />

This is basically my code, I am trying to check if the user is authenticated, if not then redirect to login page.
export const ProtectedRoute: ParentComponent = (props) => {
const { authed } = useAuth();

return authed() ? (
props.children
) : (
<Navigate href={"/login"} state={{ from: location }} />
);
};
export const ProtectedRoute: ParentComponent = (props) => {
const { authed } = useAuth();

return authed() ? (
props.children
) : (
<Navigate href={"/login"} state={{ from: location }} />
);
};
However, the problem is, I can't set replace attribute to <Navigate /> component. is there any other way to achieve same thing with or without <Navigate />
13 Replies
peerreynders
peerreynders9mo ago
useNavigate Basically use the returned navigate function even before you start rendering and set replace: true in the options argument.
kaxa
kaxaOP9mo ago
export const ProtectedRoute: ParentComponent = (props) => {
const { authed } = useAuth();
const navigate = useNavigate();
const location = useLocation();

if (!authed())
navigate("/login", {
replace: true,
state: { from: location.pathname },
});

return props.children;
};
export const ProtectedRoute: ParentComponent = (props) => {
const { authed } = useAuth();
const navigate = useNavigate();
const location = useLocation();

if (!authed())
navigate("/login", {
replace: true,
state: { from: location.pathname },
});

return props.children;
};
yep this works
Brendonovich
Brendonovich9mo ago
i'd suggest returning <>{props.children}</> as accessing children outside of jsx can cause issues
kaxa
kaxaOP9mo ago
I've refactored code to this:
export const RequireAuth: ParentComponent<{ allowedRoles: string[] }> = (
props
) => {
const { accessToken } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const decoded = accessToken()
? (jwtDecode(accessToken()) as DecodedToken)
: undefined;
const role = decoded?.role || "";

// Check if the user's role is included in the allowedRoles array
const includesRole = props.allowedRoles.includes(role);

// Redirect to login page if user is not authenticated
if (!accessToken())
navigate("/login", {
replace: true,
state: { from: location.pathname },
});
// Redirect to unauthorized page if user does not have required role
else if (!includesRole)
navigate("/unauthorized", {
replace: true,
state: { from: location.pathname },
});
else return props.children;
};
export const RequireAuth: ParentComponent<{ allowedRoles: string[] }> = (
props
) => {
const { accessToken } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const decoded = accessToken()
? (jwtDecode(accessToken()) as DecodedToken)
: undefined;
const role = decoded?.role || "";

// Check if the user's role is included in the allowedRoles array
const includesRole = props.allowedRoles.includes(role);

// Redirect to login page if user is not authenticated
if (!accessToken())
navigate("/login", {
replace: true,
state: { from: location.pathname },
});
// Redirect to unauthorized page if user does not have required role
else if (!includesRole)
navigate("/unauthorized", {
replace: true,
state: { from: location.pathname },
});
else return props.children;
};
should i still wrap props.children to empty jsx tags?
Brendonovich
Brendonovich9mo ago
Yeah Just to be safe
kaxa
kaxaOP9mo ago
Ok, it works but I had no issues without it Thanks for tip
Brendonovich
Brendonovich9mo ago
Yea it's entirely possible that it's fine without it, but if by chance children changed then that wouldn't be reflected
kaxa
kaxaOP9mo ago
I have one more question, you may know
const PersistLogin: ParentComponent = (props) => {
const [isLoading, setIsLoading] = createSignal(true);

const refresh = useRefreshToken();

const { accessToken } = useAuth();

// Resolve children when loading is completed
const resolved = children(() => !isLoading() && props.children);

... // code that sets loading state

// Show component when loading is completed
return <Show when={!isLoading()}>{resolved()}</Show>;
};
const PersistLogin: ParentComponent = (props) => {
const [isLoading, setIsLoading] = createSignal(true);

const refresh = useRefreshToken();

const { accessToken } = useAuth();

// Resolve children when loading is completed
const resolved = children(() => !isLoading() && props.children);

... // code that sets loading state

// Show component when loading is completed
return <Show when={!isLoading()}>{resolved()}</Show>;
};
Is this the correct way to resolve children, so it should proceed only when loading state has been set to false I'm not sure if this will cause issues as well
Brendonovich
Brendonovich9mo ago
Doing the isLoading check inside children() is just doing double work, I'm not sure if it's actually bad but it's defs not necessary
kaxa
kaxaOP9mo ago
I've tried without it, and it didn't show children
Brendonovich
Brendonovich9mo ago
That's good right? this should be fine
return <Show when={!isLoading()}>{props.children}</Show>;
return <Show when={!isLoading()}>{props.children}</Show>;
kaxa
kaxaOP9mo ago
Oh yeah, that totally works haha Thank you very much I've noticed that
return <Show when={!isLoading()}>{props.children}</Show>;
return <Show when={!isLoading()}>{props.children}</Show>;
and
const resolved = children(() => !isLoading() && props.children);

return <>{resolved()}</>;
const resolved = children(() => !isLoading() && props.children);

return <>{resolved()}</>;
do the same thing
Brendonovich
Brendonovich9mo ago
checks out
Want results from more Discord servers?
Add your server