Open einar-hjortdal opened 4 months ago
It might be worth using something like this
const protect = (factory: ComponentFactory) => {
return component((props = {}) => {
const { isLoggedIn } = useAuth();
useLayoutEffect(() => {
if (!isLoggedIn) {
// redirect to login page
}
}, []);
return isLoggedIn ? factory(props) : null;
});
};
export const routes = [
{
path: '/',
component: Root,
children: [
{
path: '',
component: protect(lazy(() => import('./pages/Dashboard'))),
},
{
path: 'login',
component: lazy(() => import('./pages/Login')),
},
{
path: 'not-found',
component: lazy(() => import('./pages/NotFound')),
},
{
path: '**',
redirectTo: 'not-found',
},
],
},
];
Thank you for the lead. I think I got something working
const AuthContext = createContext(null)
export const useAuth = () => useContext(AuthContext)
// Wrap app
const AuthProvider = component(({ slot }) => {
const api = useApi()
const { isFetching, data, error } = useQuery('retrieveAdmin', api.retrieveAdmin)
if (isFetching && !data) {
return <div>Loading...</div>
}
return <AuthContext value={{ isFetching, data, error }}>{slot}</AuthContext>
})
export default AuthProvider
// Wrap pages that require auth
export const withAuth = (factory) => {
return component((props) => {
const { error } = useAuth()
if (error) {
const history = useHistory()
history.push('/login')
return null
}
return factory(props)
})
}
// Login.jsx
const Login = component(() => {
const { data } = useAuth()
// redirect to dashboard if logged in
if (data) {
const history = useHistory()
history.push('/')
return null
}
return (
<>
login form
</>
)
})
I noticed that the code above doesn't actually work as expected with SSR. I think history.push doesn't work right on the server, is that correct? How is such a redirection supposed to be done on the server?
One possibility would be to only redirect on the browser, moving history.push in useEffect, but I would like the server to render the correct page.
I think history.push doesn't work right on the server, is that correct?
Such actions are usually done through effects. In reality, history.push
plans a new render, but it cannot be executed on the server.
One possibility would be to only redirect on the browser, moving history.push in useEffect
Sounds like a reasonable solution.
but I would like the server to render the correct page.
This would require the router to implement some method that would synchronously check the rights to the route when building the route tree. There is no such method in this implementation. In addition, I can’t think of a use case where it would be necessary to redirect from a protected page to a login page only through the server. What's the benefit? This is a pretty narrow scenario for SSR.
This would require the router to implement some method that would synchronously check the rights to the route when building the route tree. There is no such method in this implementation. In addition, I can’t think of a use case where it would be necessary to redirect from a protected page to a login page only through the server. What's the benefit? This is a pretty narrow scenario for SSR.
Not only through server, but on first requests to the server in a isomorphic fashion. It's mostly an optimization to immediately deliver the login page html, for a faster perceived response time. Not so important, so not going to pursue this now.
Web router expects factory functions in the
component
field, which means I cannot doI also cannot do
How does one implement "protected routes" with web-router?