To make requests to the API functions in the api
folder, we provide a
custom hook useApiRequest
, a wrapper around fetch
.
It has the following functionality:
- Uses an internal
state
to keep track of the state of the request, likeloading
,error
andsuccess
. This helps you write fetch requests the "hooks way" - Automatically adds a
Firebase AppCheck Token
to the request headers if you enabled Firebase AppCheck - Automatically adds a
CSRF token
to the request headers
Similarly to making Firestore Requests, it's a convention to create a custom hook for each request for readability/reusability reasons.
src/core/hooks/use-create-session.ts
import useApiRequest from '~/core/hooks/use-api';
interface Body {
idToken: string;
}
export function useCreateSession() {
return useApiRequest<void, Body>('/api/session/sign-in');
}
The hook returns an array with:
- the callback to make the request
- the state object of the request
const [createSession, createSessionState] = useCreateSession();
The state object internally uses useApiRequest
, and has the following
interface:
{
success: boolean;
loading: boolean;
error: string;
data: T | undefined;
}
When success
is true
, the property data
is inferred with its correct type.
You can use this hook in your components:
import { useCreateSession } from '~/core/hooks/use-create-session';
function Component() {
const [createSession, createSessionState] = useCreateSession();
return (
<>
{ createSessionState.loading ? `Loading...` : null }
{ createSessionState.error ? `Error :(` : null }
{ createSessionState.success ? `Yay, success!` : null }
<SignInForm onSignIn={(idToken) => createSession({ idToken })} />
</>
);
}
Similarly, you can also use it to fetch data:
import { useCreateSession } from '~/core/hooks/use-create-session';
function Component() {
const [fetchMembers, { loading, error, data }]
= useFetchMembers();
// fetch data when the component mounts
useEffect(() => {
fetchMembers();
}, [fetchMembers]);
if (loading) {
return <div>Fetching members...</div>;
}
if (error) {
return <div>{error}</div>;
}
return (
<div>
{data.map(member => <MemberItem member={member} />)}
</div>
);
}