LoopKitFrontend
useReviewSession
Complete study session state machine hook
Overview
useReviewSession manages the entire lifecycle of a study session through a state machine.
import { useReviewSession } from '@loopkit/react';State Machine
idle → loading → reviewing ⟷ answered → complete
↑ │
└───── (undo) ──────────┘| State | Description |
|---|---|
idle | No session active. Call startSession() to begin. |
loading | Queue is being built from the API. |
reviewing | Showing card front. Call showAnswer() to reveal. |
answered | Showing card back. Call grade() to advance. |
complete | All cards reviewed. Session summary available. |
Return Type
interface UseReviewSessionReturn {
// State
sessionState: 'idle' | 'loading' | 'reviewing' | 'answered' | 'complete';
currentCard: CardBase | null;
renderedContent: RenderedCard | null;
nextIntervals: Record<Grade, string> | null;
progress: { reviewed: number; remaining: number; total: number };
canUndo: boolean;
error: string | null;
summary: SessionSummary | null;
// Actions
startSession: (deckId: string) => Promise<void>;
showAnswer: () => void;
grade: (grade: Grade) => Promise<void>;
undo: () => Promise<void>;
endSession: () => void;
}Properties
| Property | Type | Description |
|---|---|---|
sessionState | SessionState | Current state in the state machine |
currentCard | CardBase | null | The card being reviewed |
renderedContent | RenderedCard | null | Rendered HTML { front, back } |
nextIntervals | Record<Grade, string> | null | Preview intervals for each grade |
progress | object | { reviewed, remaining, total } counts |
canUndo | boolean | Whether undo is available |
error | string | null | Last error message |
summary | SessionSummary | null | Session results (when complete) |
Actions
| Action | Description |
|---|---|
startSession(deckId) | Start a new study session for the deck |
showAnswer() | Transition from reviewing to answered |
grade(grade) | Grade the current card and advance to next |
undo() | Undo the last grade and restore the card |
endSession() | Reset to idle state |
Example: Custom Review UI
function StudyView({ deckId }: { deckId: string }) {
const {
sessionState,
renderedContent,
nextIntervals,
progress,
canUndo,
summary,
startSession,
showAnswer,
grade,
undo,
endSession,
} = useReviewSession();
switch (sessionState) {
case 'idle':
return <button onClick={() => startSession(deckId)}>Study Now</button>;
case 'loading':
return <p>Loading cards...</p>;
case 'reviewing':
return (
<div>
<p>{progress.reviewed}/{progress.total}</p>
<div dangerouslySetInnerHTML={{ __html: renderedContent?.front ?? '' }} />
<button onClick={showAnswer}>Show Answer</button>
{canUndo && <button onClick={undo}>Undo</button>}
</div>
);
case 'answered':
return (
<div>
<div dangerouslySetInnerHTML={{ __html: renderedContent?.back ?? '' }} />
<div>
<button onClick={() => grade('again')}>
Again ({nextIntervals?.again})
</button>
<button onClick={() => grade('hard')}>
Hard ({nextIntervals?.hard})
</button>
<button onClick={() => grade('good')}>
Good ({nextIntervals?.good})
</button>
<button onClick={() => grade('easy')}>
Easy ({nextIntervals?.easy})
</button>
</div>
</div>
);
case 'complete':
return (
<div>
<h2>Session Complete</h2>
<p>Reviewed: {summary?.totalReviewed}</p>
<p>Correct: {summary?.correctCount}</p>
<button onClick={endSession}>Done</button>
</div>
);
}
}