T
TanStack13mo ago
foreign-sapphire

Error using ensureQueryData

ive been developing my app for long time using tanstack router and query, and im having problems in the part of handling authentication, my app works perfectly but when, the access token expired then the problem appears, i made my backend with rust and i made an endpoint to check the status of the cookies to see if the tokens are valid, so in the frontend im trying to handle this in the AuthContext, and then i checked the doc of tanstack to follow how do i face this problem but nothing, if anyone can help me because its a nightmare, and thanks.
No description
No description
No description
3 Replies
foreign-sapphire
foreign-sapphireOP13mo ago
export function AuthContextProvider({
children,
}: {
children: React.ReactNode;
}) {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [isAuthenticating, setIsAuthenticating] = useState<boolean>(true);
const [sessionStatus, setSessionStatus] = useState<
"access" | "refresh" | "login"
>("login");

const checkSessionStatus = async () => {
setIsAuthenticating(true);

try {
const response = await fetch(`${baseUrl}/session_status`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
});

const data = (await response.json()) as {
status: "access" | "refresh" | "login";
};

if (response.status === 401 || data.status === "login") {
setIsAuthenticated(false);
setSessionStatus("login");
window.location.href = "/auth/login";
return;
} else if (data.status === "refresh") {
setIsAuthenticated(false);
setSessionStatus("refresh");
window.location.href = "/auth/refresh";
return;
}

setSessionStatus("access");
setIsAuthenticated(true);
} catch (error) {
setIsAuthenticated(false);
setSessionStatus("login");
window.location.href = "/auth/login";
return;
} finally {
setIsAuthenticating(false);
}
};

return (
<AuthContext.Provider
value={{
isAuthenticated,
checkSessionStatus,
sessionStatus,
isAuthenticating,
}}
>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = React.useContext(AuthContext);

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

return context;
}
export function AuthContextProvider({
children,
}: {
children: React.ReactNode;
}) {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [isAuthenticating, setIsAuthenticating] = useState<boolean>(true);
const [sessionStatus, setSessionStatus] = useState<
"access" | "refresh" | "login"
>("login");

const checkSessionStatus = async () => {
setIsAuthenticating(true);

try {
const response = await fetch(`${baseUrl}/session_status`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
});

const data = (await response.json()) as {
status: "access" | "refresh" | "login";
};

if (response.status === 401 || data.status === "login") {
setIsAuthenticated(false);
setSessionStatus("login");
window.location.href = "/auth/login";
return;
} else if (data.status === "refresh") {
setIsAuthenticated(false);
setSessionStatus("refresh");
window.location.href = "/auth/refresh";
return;
}

setSessionStatus("access");
setIsAuthenticated(true);
} catch (error) {
setIsAuthenticated(false);
setSessionStatus("login");
window.location.href = "/auth/login";
return;
} finally {
setIsAuthenticating(false);
}
};

return (
<AuthContext.Provider
value={{
isAuthenticated,
checkSessionStatus,
sessionStatus,
isAuthenticating,
}}
>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = React.useContext(AuthContext);

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

return context;
}
thats my context
spiritual-aqua
spiritual-aqua13mo ago
please provide a minimal complete example by forking on of the existing examples on stackblitz. otherwise we cannot debug this
foreign-sapphire
foreign-sapphireOP13mo ago
const urlsQueryOptions = (
limit: number,
offset: number,
category: UrlCategories,
) =>
queryOptions({
//important to include the queries, with the purpose to invalidate and refetch with a unique key.
queryKey: ["urls", { limit, offset, category }],
queryFn: () => getAllUrl(limit, offset, category),
});


export const Route = createFileRoute("/_authed/dashboard/")({
validateSearch: (search: Record<string, unknown>): UrlSearchOptions => {
return {
limit: Number(search?.limit ?? 15),
offset: Number(search?.offset ?? 0),
category: (search?.category as UrlCategories) || UrlCategories.All,
};
},

loaderDeps: ({ search }) => {
return {
limit: search.limit,
offset: search.offset,
category: search.category,
};
},

loader: async ({ context, deps: { limit, offset, category } }) => {
//here is the error, the query its been called even though the autehntication is not done.

if (context.auth?.isAuthenticated === true) {
const urls = await context.queryClient.prefetchQuery(
urlsQueryOptions(limit, offset, category),
);
return {
urls,
};
}
},
pendingComponent: () => <div>Loading...</div>,

errorComponent: UrlsErrorComponent,

component: Dashboard,
});

function Dashboard() {
const searchProps = Route.useSearch();
const {
data: urls,
isLoading,
error,
isError,
} = useSuspenseQuery(
urlsQueryOptions(
searchProps.limit,
searchProps.offset,
searchProps.category,
),
);

if (isLoading) {
return <div>Loading...</div>;
}

console.log("error from index", isError);

return (
<>
<div className="p-4 sm:ml-64">
<div className="p-4 rounded-lg min-h-[calc(100vh-3.5rem)]">
<DashboardMain urls={urls} searchQueries={searchProps} />
<Outlet />
</div>
</div>
</>
);
}
const urlsQueryOptions = (
limit: number,
offset: number,
category: UrlCategories,
) =>
queryOptions({
//important to include the queries, with the purpose to invalidate and refetch with a unique key.
queryKey: ["urls", { limit, offset, category }],
queryFn: () => getAllUrl(limit, offset, category),
});


export const Route = createFileRoute("/_authed/dashboard/")({
validateSearch: (search: Record<string, unknown>): UrlSearchOptions => {
return {
limit: Number(search?.limit ?? 15),
offset: Number(search?.offset ?? 0),
category: (search?.category as UrlCategories) || UrlCategories.All,
};
},

loaderDeps: ({ search }) => {
return {
limit: search.limit,
offset: search.offset,
category: search.category,
};
},

loader: async ({ context, deps: { limit, offset, category } }) => {
//here is the error, the query its been called even though the autehntication is not done.

if (context.auth?.isAuthenticated === true) {
const urls = await context.queryClient.prefetchQuery(
urlsQueryOptions(limit, offset, category),
);
return {
urls,
};
}
},
pendingComponent: () => <div>Loading...</div>,

errorComponent: UrlsErrorComponent,

component: Dashboard,
});

function Dashboard() {
const searchProps = Route.useSearch();
const {
data: urls,
isLoading,
error,
isError,
} = useSuspenseQuery(
urlsQueryOptions(
searchProps.limit,
searchProps.offset,
searchProps.category,
),
);

if (isLoading) {
return <div>Loading...</div>;
}

console.log("error from index", isError);

return (
<>
<div className="p-4 sm:ml-64">
<div className="p-4 rounded-lg min-h-[calc(100vh-3.5rem)]">
<DashboardMain urls={urls} searchQueries={searchProps} />
<Outlet />
</div>
</div>
</>
);
}
my dashboard I understand I’ll do it

Did you find this page helpful?