Overview
The ZKScore React SDK provides a comprehensive set of hooks that make it easy to integrate reputation scores, identities, achievements, and more into your React applications.
Installation
npm install @zkscore/react
Provider Setup
Wrap your app with the ZKScoreProvider:
import { ZKScoreProvider } from '@zkscore/react';
function App() {
return (
<ZKScoreProvider
apiKey={process.env.REACT_APP_ZKSCORE_API_KEY}
network="mainnet"
>
<YourApp />
</ZKScoreProvider>
);
}
Provider Props
Network to use: 'mainnet' or 'testnet' (default: 'mainnet')
Cache duration in milliseconds (default: 300000 - 5 minutes)
Number of retry attempts for failed requests (default: 3)
Available Hooks
Identity Hooks
Score Hooks
Achievement Hooks
Trading Hooks
Trust Layer Hooks
Hook Patterns
Basic Usage
import { useScore } from '@zkscore/react';
function ScoreDisplay({ address }: { address: string }) {
const { score, loading, error } = useScore(address);
if (loading) return <div>Loading score...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!score) return <div>No score available</div>;
return (
<div>
<h2>Score: {score.overall}/1000</h2>
<p>Rank: #{score.rank}</p>
</div>
);
}
With Auto-Refresh
import { useScore } from '@zkscore/react';
function LiveScore({ address }: { address: string }) {
const { score, loading, refetch } = useScore(address, {
refreshInterval: 30000, // Refresh every 30 seconds
});
return (
<div>
<h2>Score: {score?.overall || 0}</h2>
<button onClick={() => refetch()}>Refresh Now</button>
</div>
);
}
Conditional Fetching
import { useScore } from '@zkscore/react';
function ConditionalScore({ address, enabled }: { address: string; enabled: boolean }) {
const { score, loading } = useScore(address, {
enabled, // Only fetch when enabled is true
});
if (!enabled) return <div>Score fetching disabled</div>;
if (loading) return <div>Loading...</div>;
return <div>Score: {score?.overall}</div>;
}
Error Handling
import { useScore } from '@zkscore/react';
function ScoreWithErrorHandling({ address }: { address: string }) {
const { score, loading, error, refetch } = useScore(address, {
retry: 3,
retryDelay: 1000,
});
if (loading) return <Spinner />;
if (error) {
return (
<ErrorCard>
<p>{error.message}</p>
<button onClick={() => refetch()}>Try Again</button>
</ErrorCard>
);
}
return <ScoreCard score={score} />;
}
Multiple Hooks
import { useIdentity, useScore, useUserAchievements } from '@zkscore/react';
function UserProfile({ address }: { address: string }) {
const { identity } = useIdentity(address);
const { score } = useScore(address);
const { achievements } = useUserAchievements(address);
return (
<div>
<h1>{identity?.username || 'Anonymous'}</h1>
<p>Score: {score?.overall}/1000</p>
<p>Achievements: {achievements?.length || 0}</p>
</div>
);
}
Common Hook Options
Most hooks accept these common options:
Enable/disable the query (default: true)
Auto-refresh interval in milliseconds
Number of retry attempts (default: 3)
Delay between retries in milliseconds (default: 1000)
How long to cache data in milliseconds
Time until data is considered stale in milliseconds
Callback when query succeeds
Callback when query fails
Common Return Values
All hooks return an object with these common properties:
The fetched data (e.g., score, identity, achievements)
Whether the data is currently being fetched
Error object if the request failed
Function to manually refetch the data
Whether the cached data is stale
Advanced Patterns
Prefetching Data
import { useZKScore } from '@zkscore/react';
function PrefetchExample() {
const { prefetch } = useZKScore();
const handleMouseEnter = (address: string) => {
// Prefetch data on hover
prefetch.score(address);
prefetch.achievements(address);
};
return (
<div onMouseEnter={() => handleMouseEnter('0x123...')}>
<UserCard address="0x123..." />
</div>
);
}
Mutations
import { useMintIdentity } from '@zkscore/react';
function MintIdentityForm() {
const { mutate, loading, error } = useMintIdentity({
onSuccess: (identity) => {
console.log('Identity minted:', identity);
},
onError: (error) => {
console.error('Failed to mint:', error);
},
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
mutate({
address: '0x123...',
username: 'alice',
});
};
return (
<form onSubmit={handleSubmit}>
<input name="username" required />
<button type="submit" disabled={loading}>
{loading ? 'Minting...' : 'Mint Identity'}
</button>
{error && <p className="error">{error.message}</p>}
</form>
);
}
Optimistic Updates
import { useClaimAchievement, useUserAchievements } from '@zkscore/react';
function ClaimButton({ address, achievementId }: Props) {
const { achievements, refetch } = useUserAchievements(address);
const { mutate } = useClaimAchievement({
onMutate: () => {
// Optimistically update UI
// This runs before the API call
},
onSuccess: () => {
// Refetch to get updated data
refetch();
},
});
return (
<button onClick={() => mutate({ achievementId })}>
Claim Achievement
</button>
);
}
Dependent Queries
import { useIdentity, useScore } from '@zkscore/react';
function DependentQueries({ address }: { address: string }) {
// First query
const { identity } = useIdentity(address);
// Second query only runs if first succeeds
const { score } = useScore(address, {
enabled: !!identity,
});
return (
<div>
{identity && <h1>{identity.username}</h1>}
{score && <p>Score: {score.overall}</p>}
</div>
);
}
import { useTradingHistory } from '@zkscore/react';
import { useState } from 'react';
function TradingHistoryTable({ address }: { address: string }) {
const [page, setPage] = useState(0);
const { history, loading, pagination } = useTradingHistory(address, {
limit: 20,
offset: page * 20,
});
return (
<div>
{loading ? (
<Spinner />
) : (
<table>
{history?.trades.map((trade) => (
<tr key={trade.txHash}>
<td>{trade.tokenIn.symbol}</td>
<td>{trade.tokenOut.symbol}</td>
<td>{trade.timestamp}</td>
</tr>
))}
</table>
)}
<Pagination
page={page}
hasMore={pagination?.hasMore}
onNext={() => setPage(p => p + 1)}
onPrev={() => setPage(p => Math.max(0, p - 1))}
/>
</div>
);
}
TypeScript Support
All hooks are fully typed for TypeScript:
import { useScore } from '@zkscore/react';
import type { Score, ScoreBreakdown } from '@zkscore/types';
function TypedScore({ address }: { address: string }) {
// Type is inferred automatically
const { score, loading, error } = useScore(address);
// score is typed as Score | undefined
// error is typed as Error | null
// loading is typed as boolean
return <div>{score?.overall}</div>;
}
- Use Appropriate Cache Times: Set longer cache times for rarely-changing data
- Disable Auto-Refetch: For static data, set
refreshInterval: 0
- Enable Suspense: Use React Suspense for better loading states
- Prefetch: Prefetch data on hover or route changes
- Batch Requests: Use multiple hooks to fetch related data in parallel
Next Steps