Aller au contenu principal
Version : 11.x

useSubscription()

Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

Le hook useSubscription permet de s'abonner à une procédure d'abonnement sur le serveur.

Signature

Options

astuce
  • Si vous devez configurer des options sans transmettre d'entrée, passez undefined.
  • En passant skipToken de @tanstack/react-query, l'abonnement sera mis en pause.
  • Consultez notre exemple SSE pour un cas complet d'utilisation des abonnements
tsx
interface UseTRPCSubscriptionOptions<TOutput, TError> {
/**
* Called when the subscription is started.
*/
onStarted?: () => void;
/**
* Called when new data is received from the subscription.
*/
onData?: (data: TOutput) => void;
/**
* Called when an **unrecoverable error** occurs and the subscription is stopped.
*/
onError?: (error: TError) => void;
/**
* Called when the subscription is completed on the server.
* The state will transition to `'idle'` with `data: undefined`.
*/
onComplete?: () => void;
/**
* @deprecated Use a `skipToken` from `@tanstack/react-query` instead.
* This will be removed in v12.
*/
enabled?: boolean;
}
tsx
interface UseTRPCSubscriptionOptions<TOutput, TError> {
/**
* Called when the subscription is started.
*/
onStarted?: () => void;
/**
* Called when new data is received from the subscription.
*/
onData?: (data: TOutput) => void;
/**
* Called when an **unrecoverable error** occurs and the subscription is stopped.
*/
onError?: (error: TError) => void;
/**
* Called when the subscription is completed on the server.
* The state will transition to `'idle'` with `data: undefined`.
*/
onComplete?: () => void;
/**
* @deprecated Use a `skipToken` from `@tanstack/react-query` instead.
* This will be removed in v12.
*/
enabled?: boolean;
}

Type de retour

Le type de retour est une union discriminée sur status :

ts
type TRPCSubscriptionResult<TOutput, TError> =
| TRPCSubscriptionIdleResult<TOutput>
| TRPCSubscriptionConnectingResult<TOutput, TError>
| TRPCSubscriptionPendingResult<TOutput>
| TRPCSubscriptionErrorResult<TOutput, TError>;
 
interface TRPCSubscriptionIdleResult<TOutput> {
/** Subscription is disabled or has ended */
status: 'idle';
data: undefined;
error: null;
reset: () => void;
}
 
interface TRPCSubscriptionConnectingResult<TOutput, TError> {
/** Trying to establish a connection (may have a previous error from a reconnection attempt) */
status: 'connecting';
data: TOutput | undefined;
error: TError | null;
reset: () => void;
}
 
interface TRPCSubscriptionPendingResult<TOutput> {
/** Connected to the server, receiving data */
status: 'pending';
data: TOutput | undefined;
error: null;
reset: () => void;
}
 
interface TRPCSubscriptionErrorResult<TOutput, TError> {
/** An unrecoverable error occurred and the subscription is stopped */
status: 'error';
data: TOutput | undefined;
error: TError;
reset: () => void;
}
ts
type TRPCSubscriptionResult<TOutput, TError> =
| TRPCSubscriptionIdleResult<TOutput>
| TRPCSubscriptionConnectingResult<TOutput, TError>
| TRPCSubscriptionPendingResult<TOutput>
| TRPCSubscriptionErrorResult<TOutput, TError>;
 
interface TRPCSubscriptionIdleResult<TOutput> {
/** Subscription is disabled or has ended */
status: 'idle';
data: undefined;
error: null;
reset: () => void;
}
 
interface TRPCSubscriptionConnectingResult<TOutput, TError> {
/** Trying to establish a connection (may have a previous error from a reconnection attempt) */
status: 'connecting';
data: TOutput | undefined;
error: TError | null;
reset: () => void;
}
 
interface TRPCSubscriptionPendingResult<TOutput> {
/** Connected to the server, receiving data */
status: 'pending';
data: TOutput | undefined;
error: null;
reset: () => void;
}
 
interface TRPCSubscriptionErrorResult<TOutput, TError> {
/** An unrecoverable error occurred and the subscription is stopped */
status: 'error';
data: TOutput | undefined;
error: TError;
reset: () => void;
}

Exemple de procédure

server/routers/_app.ts
tsx
import EventEmitter, { on } from 'events';
import { initTRPC } from '@trpc/server';
 
export const t = initTRPC.create();
 
type Post = { id: string; title: string };
const ee = new EventEmitter();
 
export const appRouter = t.router({
onPostAdd: t.procedure.subscription(async function* (opts) {
for await (const [data] of on(ee, 'add', {
signal: opts.signal,
})) {
const post = data as Post;
yield post;
}
}),
});
 
export type AppRouter = typeof appRouter;
server/routers/_app.ts
tsx
import EventEmitter, { on } from 'events';
import { initTRPC } from '@trpc/server';
 
export const t = initTRPC.create();
 
type Post = { id: string; title: string };
const ee = new EventEmitter();
 
export const appRouter = t.router({
onPostAdd: t.procedure.subscription(async function* (opts) {
for await (const [data] of on(ee, 'add', {
signal: opts.signal,
})) {
const post = data as Post;
yield post;
}
}),
});
 
export type AppRouter = typeof appRouter;

Exemple de composant React

components/PostFeed.tsx
tsx
import { trpc } from '../utils/trpc';
 
type Post = { id: string; title: string };
 
export function PostFeed() {
const [posts, setPosts] = React.useState<Post[]>([]);
 
const subscription = trpc.onPostAdd.useSubscription(undefined, {
onData: (post) => {
setPosts((prev) => [...prev, post]);
},
});
 
return (
<div>
<h1>Live Feed</h1>
{subscription.status === 'connecting' && <p>Connecting...</p>}
{subscription.status === 'error' && (
<div>
<p>Error: {subscription.error.message}</p>
<button onClick={() => subscription.reset()}>Reconnect</button>
</div>
)}
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
components/PostFeed.tsx
tsx
import { trpc } from '../utils/trpc';
 
type Post = { id: string; title: string };
 
export function PostFeed() {
const [posts, setPosts] = React.useState<Post[]>([]);
 
const subscription = trpc.onPostAdd.useSubscription(undefined, {
onData: (post) => {
setPosts((prev) => [...prev, post]);
},
});
 
return (
<div>
<h1>Live Feed</h1>
{subscription.status === 'connecting' && <p>Connecting...</p>}
{subscription.status === 'error' && (
<div>
<p>Error: {subscription.error.message}</p>
<button onClick={() => subscription.reset()}>Reconnect</button>
</div>
)}
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}