My App
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) ──────────┘
StateDescription
idleNo session active. Call startSession() to begin.
loadingQueue is being built from the API.
reviewingShowing card front. Call showAnswer() to reveal.
answeredShowing card back. Call grade() to advance.
completeAll 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

PropertyTypeDescription
sessionStateSessionStateCurrent state in the state machine
currentCardCardBase | nullThe card being reviewed
renderedContentRenderedCard | nullRendered HTML { front, back }
nextIntervalsRecord<Grade, string> | nullPreview intervals for each grade
progressobject{ reviewed, remaining, total } counts
canUndobooleanWhether undo is available
errorstring | nullLast error message
summarySessionSummary | nullSession results (when complete)

Actions

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

On this page