Skip to main content

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

apiKey
string
required
Your ZKScore API key
network
string
Network to use: 'mainnet' or 'testnet' (default: 'mainnet')
cacheTime
number
Cache duration in milliseconds (default: 300000 - 5 minutes)
retryAttempts
number
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:
enabled
boolean
Enable/disable the query (default: true)
refreshInterval
number
Auto-refresh interval in milliseconds
retry
number
Number of retry attempts (default: 3)
retryDelay
number
Delay between retries in milliseconds (default: 1000)
cacheTime
number
How long to cache data in milliseconds
staleTime
number
Time until data is considered stale in milliseconds
onSuccess
function
Callback when query succeeds
onError
function
Callback when query fails

Common Return Values

All hooks return an object with these common properties:
data
any
The fetched data (e.g., score, identity, achievements)
loading
boolean
Whether the data is currently being fetched
error
Error | null
Error object if the request failed
refetch
function
Function to manually refetch the data
isStale
boolean
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>
  );
}

Pagination

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>;
}

Performance Tips

  1. Use Appropriate Cache Times: Set longer cache times for rarely-changing data
  2. Disable Auto-Refetch: For static data, set refreshInterval: 0
  3. Enable Suspense: Use React Suspense for better loading states
  4. Prefetch: Prefetch data on hover or route changes
  5. Batch Requests: Use multiple hooks to fetch related data in parallel

Next Steps