T
TanStack16mo ago
probable-pink

Flashing on refresh on a protected route

why is the page flashing before redirecting on refresh?
import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";
import { validateSessionCookie } from "../../utils/session";
import { getAuthSessionCookie } from "@blazar/helpers";
import { apiTreaty } from "@blazar/elysia";
import { useAuth } from "../../auth";

const AuthLayout = () => {
return (
<div className="flex justify-center items-center h-screen">
<Outlet />
</div>
);
};

export const Route = createFileRoute("/auth/_layout")({
component: AuthLayout,
beforeLoad: async ({ context }) => {
const { session, loading } = context.auth;

if (loading) {
return false;
}

if (session) {
throw redirect({
to: "/",
});
}

return true;
},
});
import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";
import { validateSessionCookie } from "../../utils/session";
import { getAuthSessionCookie } from "@blazar/helpers";
import { apiTreaty } from "@blazar/elysia";
import { useAuth } from "../../auth";

const AuthLayout = () => {
return (
<div className="flex justify-center items-center h-screen">
<Outlet />
</div>
);
};

export const Route = createFileRoute("/auth/_layout")({
component: AuthLayout,
beforeLoad: async ({ context }) => {
const { session, loading } = context.auth;

if (loading) {
return false;
}

if (session) {
throw redirect({
to: "/",
});
}

return true;
},
});
6 Replies
probable-pink
probable-pinkOP16mo ago
And here's the context for auth:
export interface AuthContext {
session: DatabaseSessionAttributes | null;
user: DatabaseUserAttributes | null;
loading: boolean;
updateAuthState: () => Promise<void>;
signOut: () => Promise<void>;
}

const AuthContext = createContext<AuthContext | null>(null);

const fetchSession = async () => {
const authCookieValue = getAuthSessionCookie("auth_session");

if (!authCookieValue) {
return null;
}

const { data, error } = await apiTreaty.api.auth["validate-session"].post({
sessionId: authCookieValue,
});

if (error) {
return null;
}

return data;
};

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [session, setSession] = useState<DatabaseSessionAttributes | null>(
null
);
const [user, setUser] = useState<DatabaseUserAttributes | null>(null);
const [loading, setLoading] = useState(true);

const updateAuthState = useCallback(async () => {
setLoading(true);

const sessionData = await fetchSession();
console.log("fetching");

if (!sessionData) {
setSession(null);
setUser(null);
console.log("setting null");

setLoading(false);
return;
}

const { session, user } = sessionData;

setSession(session);
setUser(user);
console.log("setting session and user");

setLoading(false);
}, [session, user]);

useEffect(() => {
const setIntialAuthState = async () => {
await updateAuthState();
};

setIntialAuthState();

console.log(user, session);
}, []);

return (
<AuthContext.Provider
value={{ session, user, loading, updateAuthState, signOut }}
>
{children}
</AuthContext.Provider>
);
};

export const useAuth = () => {
const context = useContext(AuthContext);

if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}

return context;
};
export interface AuthContext {
session: DatabaseSessionAttributes | null;
user: DatabaseUserAttributes | null;
loading: boolean;
updateAuthState: () => Promise<void>;
signOut: () => Promise<void>;
}

const AuthContext = createContext<AuthContext | null>(null);

const fetchSession = async () => {
const authCookieValue = getAuthSessionCookie("auth_session");

if (!authCookieValue) {
return null;
}

const { data, error } = await apiTreaty.api.auth["validate-session"].post({
sessionId: authCookieValue,
});

if (error) {
return null;
}

return data;
};

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [session, setSession] = useState<DatabaseSessionAttributes | null>(
null
);
const [user, setUser] = useState<DatabaseUserAttributes | null>(null);
const [loading, setLoading] = useState(true);

const updateAuthState = useCallback(async () => {
setLoading(true);

const sessionData = await fetchSession();
console.log("fetching");

if (!sessionData) {
setSession(null);
setUser(null);
console.log("setting null");

setLoading(false);
return;
}

const { session, user } = sessionData;

setSession(session);
setUser(user);
console.log("setting session and user");

setLoading(false);
}, [session, user]);

useEffect(() => {
const setIntialAuthState = async () => {
await updateAuthState();
};

setIntialAuthState();

console.log(user, session);
}, []);

return (
<AuthContext.Provider
value={{ session, user, loading, updateAuthState, signOut }}
>
{children}
</AuthContext.Provider>
);
};

export const useAuth = () => {
const context = useContext(AuthContext);

if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}

return context;
};
itchy-amethyst
itchy-amethyst16mo ago
can you please provide a complete minimal example by forking one of the existing examples on stackblitz?
probable-pink
probable-pinkOP16mo ago
it would be very difficult since im using custom built api etc. but ill try to simulate some behaviors so it might work. give me a sec
probable-pink
probable-pinkOP16mo ago
StackBlitz
Router Authenticated Routes Example (forked) - StackBlitz
Run official live example code for Router Authenticated Routes, created by Tanstack on StackBlitz
itchy-amethyst
itchy-amethyst16mo ago
can't you make the session a promise that you await?
probable-pink
probable-pinkOP16mo ago
i just used the loading state on the component for now. it works but its not perfect

Did you find this page helpful?