useArchiva Hook
The useArchiva hook provides access to the Archiva context in client components. Use it when you need to build custom event displays or integrate Archiva into your own components.
When to Use It
Use the useArchiva hook when:
- You want to build a custom event display (not using the Timeline component)
- You need to fetch events programmatically
- You want to integrate Archiva into existing components
- You need access to tokens for custom API calls
If you just want to display events, the Timeline component is easier and handles everything for you.
Basic Usage
'use client';
import { useArchiva } from '@archiva/archiva-nextjs/react/client';
export function CustomComponent() {
const { apiBaseUrl, getToken, forceRefreshToken } = useArchiva();
// Use the context values...
}
Return Value
The hook returns an object with:
| Property | Type | Description |
|---|---|---|
apiBaseUrl | string | Base URL for the Archiva API (e.g., 'https://api.archiva.app') |
getToken | () => Promise<string> | Get current frontend token (cached if valid, fetches new one if expired) |
forceRefreshToken | () => Promise<string> | Force refresh the frontend token (bypasses cache) |
projectId | string | undefined | Project ID if provided to ArchivaProvider |
Examples
Fetching Events Manually
Build a custom event list:
'use client';
import { useArchiva } from '@archiva/archiva-nextjs/react/client';
import { useState, useEffect } from 'react';
export function CustomEventList({ entityId }: { entityId: string }) {
const { apiBaseUrl, getToken } = useArchiva();
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function loadEvents() {
try {
setLoading(true);
const token = await getToken();
const response = await fetch(
`${apiBaseUrl}/api/events?entityId=${entityId}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
if (!response.ok) {
throw new Error(`Failed to load events: ${response.statusText}`);
}
const data = await response.json();
setEvents(data.items);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
}
loadEvents();
}, [entityId, apiBaseUrl, getToken]);
if (loading) return <div>Loading events...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{events.map((event) => (
<li key={event.id}>
{event.actionKey} - {event.receivedAt}
</li>
))}
</ul>
);
}
Manual Token Refresh
Force a token refresh when needed:
'use client';
import { useArchiva } from '@archiva/archiva-nextjs/react/client';
export function RefreshButton() {
const { forceRefreshToken } = useArchiva();
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
try {
setRefreshing(true);
const newToken = await forceRefreshToken();
console.log('Token refreshed:', newToken);
// Token is now cached and ready to use
} catch (error) {
console.error('Failed to refresh token:', error);
} finally {
setRefreshing(false);
}
};
return (
<button onClick={handleRefresh} disabled={refreshing}>
{refreshing ? 'Refreshing...' : 'Refresh Token'}
</button>
);
}
Using API Base URL
Access the configured API base URL:
'use client';
import { useArchiva } from '@archiva/archiva-nextjs/react/client';
export function ApiInfo() {
const { apiBaseUrl } = useArchiva();
return <div>Connected to: {apiBaseUrl}</div>;
}
Pagination Example
Implement custom pagination:
'use client';
import { useArchiva } from '@archiva/archiva-nextjs/react/client';
import { useState, useEffect } from 'react';
export function PaginatedEventList() {
const { apiBaseUrl, getToken } = useArchiva();
const [events, setEvents] = useState([]);
const [cursor, setCursor] = useState<string | undefined>();
const [loading, setLoading] = useState(false);
const loadMore = async () => {
setLoading(true);
try {
const token = await getToken();
const params = new URLSearchParams({ limit: '25' });
if (cursor) params.set('cursor', cursor);
const response = await fetch(
`${apiBaseUrl}/api/events?${params}`,
{
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await response.json();
setEvents((prev) => [...prev, ...data.items]);
setCursor(data.nextCursor);
} finally {
setLoading(false);
}
};
useEffect(() => {
loadMore();
}, []);
return (
<div>
{events.map((event) => (
<div key={event.id}>{event.actionKey}</div>
))}
{cursor && (
<button onClick={loadMore} disabled={loading}>
{loading ? 'Loading...' : 'Load More'}
</button>
)}
</div>
);
}
Token Management
getToken()
Gets the current frontend token. If a valid token is cached, it returns immediately. If the token is expired or missing, it automatically fetches a new one.
Why use this? The SDK handles token caching and refresh automatically. You don't need to worry about token expiration—just call getToken() whenever you need to make an API request.
forceRefreshToken()
Forces a token refresh, bypassing the cache. Use this when:
- You suspect the current token is invalid
- You want to ensure you have a fresh token
- You're debugging token issues
Note: In most cases, getToken() is sufficient. The SDK automatically refreshes tokens 30 seconds before they expire.
Error Handling
The hook will throw an error if:
- Used outside of an
ArchivaProvider - Token endpoint returns an error
- Network request fails
Always wrap token calls in try/catch:
try {
const token = await getToken();
// Use token...
} catch (error) {
// Handle error (e.g., show error message to user)
}
Requirements
- Must be used within an
ArchivaProvider(see ArchivaProvider) - Must be in a client component (use
'use client'directive) - Requires the frontend token route to be set up (see Frontend Token Route)
Import Path
Important: Always import from the client entrypoint:
import { useArchiva } from '@archiva/archiva-nextjs/react/client';
Do NOT import from the root package or /react in client components.
Next Steps
- Learn about the Timeline component for ready-made UI
- See a complete example in action
- Explore the ArchivaProvider setup