or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

hook-creation.mdindex.mdmutation-hooks.mdquery-hooks.mdquery-keys.mdquery-utilities.mdreact-server-components.mdserver-side-helpers.mdsubscription-hooks.md

query-utilities.mddocs/

0

# Query Utilities

1

2

Comprehensive utility functions for imperative query operations and cache management. These utilities are accessed through the `useUtils()` hook and provide programmatic control over React Query's cache and data fetching.

3

4

## Capabilities

5

6

### useUtils Hook

7

8

Primary hook for accessing query utilities and cache management functions.

9

10

```typescript { .api }

11

/**

12

* Hook that provides access to query utilities for imperative operations

13

* @returns Object with utility functions mirroring your router structure

14

*/

15

function useUtils(): CreateReactUtils<TRouter, TSSRContext>;

16

17

// Legacy alias (deprecated)

18

function useContext(): CreateReactUtils<TRouter, TSSRContext>;

19

20

interface CreateReactUtils<TRouter, TSSRContext> {

21

// Utility functions are generated based on your router structure

22

// Each procedure gets a set of utility methods

23

}

24

```

25

26

**Usage Examples:**

27

28

```typescript

29

import { trpc } from "./utils/trpc";

30

31

function UserManagement() {

32

const utils = trpc.useUtils();

33

34

const handleRefreshUser = (userId: number) => {

35

// Refetch specific user data

36

utils.user.get.refetch({ id: userId });

37

};

38

39

const handleInvalidateUsers = () => {

40

// Invalidate all user-related queries

41

utils.user.invalidate();

42

};

43

44

return (

45

<div>

46

<button onClick={() => handleRefreshUser(1)}>

47

Refresh User 1

48

</button>

49

<button onClick={handleInvalidateUsers}>

50

Refresh All User Data

51

</button>

52

</div>

53

);

54

}

55

```

56

57

### Query Invalidation

58

59

Invalidate cached queries to trigger refetching when data may be stale.

60

61

```typescript { .api }

62

/**

63

* Invalidate queries to trigger refetching

64

* @param input - Optional input to target specific queries

65

* @param opts - Invalidation options

66

* @returns Promise that resolves when invalidation is complete

67

*/

68

procedure.invalidate(

69

input?: GetQueryProcedureInput<TInput>,

70

opts?: InvalidateQueryFilters & RefetchOptions

71

): Promise<void>;

72

73

interface InvalidateQueryFilters {

74

type?: QueryType;

75

exact?: boolean;

76

predicate?: (query: Query) => boolean;

77

}

78

```

79

80

**Usage Examples:**

81

82

```typescript

83

function InvalidationExamples() {

84

const utils = trpc.useUtils();

85

86

const invalidateExamples = {

87

// Invalidate all user queries

88

invalidateAllUsers: () => utils.user.invalidate(),

89

90

// Invalidate specific user query

91

invalidateSpecificUser: (userId: number) =>

92

utils.user.get.invalidate({ id: userId }),

93

94

// Invalidate with options

95

invalidateWithOptions: () =>

96

utils.user.list.invalidate(undefined, {

97

type: 'active', // Only invalidate active queries

98

refetchType: 'active',

99

}),

100

101

// Invalidate multiple related queries

102

invalidateUserData: async (userId: number) => {

103

await Promise.all([

104

utils.user.get.invalidate({ id: userId }),

105

utils.user.posts.invalidate({ userId }),

106

utils.user.settings.invalidate({ userId }),

107

]);

108

},

109

};

110

111

return (

112

<div>

113

<button onClick={invalidateExamples.invalidateAllUsers}>

114

Invalidate All Users

115

</button>

116

<button onClick={() => invalidateExamples.invalidateSpecificUser(1)}>

117

Invalidate User 1

118

</button>

119

</div>

120

);

121

}

122

```

123

124

### Query Refetching

125

126

Explicitly refetch queries to get fresh data from the server.

127

128

```typescript { .api }

129

/**

130

* Refetch queries to get fresh data

131

* @param input - Optional input to target specific queries

132

* @param opts - Refetch options

133

* @returns Promise that resolves when refetch is complete

134

*/

135

procedure.refetch(

136

input?: GetQueryProcedureInput<TInput>,

137

opts?: RefetchOptions

138

): Promise<void>;

139

140

interface RefetchOptions {

141

type?: 'active' | 'inactive' | 'all';

142

cancelRefetch?: boolean;

143

}

144

```

145

146

**Usage Examples:**

147

148

```typescript

149

function RefetchExamples() {

150

const utils = trpc.useUtils();

151

152

const refetchExamples = {

153

// Refetch all user queries

154

refetchAllUsers: () => utils.user.refetch(),

155

156

// Refetch specific user

157

refetchSpecificUser: (userId: number) =>

158

utils.user.get.refetch({ id: userId }),

159

160

// Refetch with options

161

refetchActive: () =>

162

utils.user.list.refetch(undefined, { type: 'active' }),

163

164

// Conditional refetch

165

conditionalRefetch: async (userId: number) => {

166

const userData = utils.user.get.getData({ id: userId });

167

if (!userData || isStale(userData)) {

168

await utils.user.get.refetch({ id: userId });

169

}

170

},

171

};

172

173

return (

174

<div>

175

<button onClick={refetchExamples.refetchAllUsers}>

176

Refetch All Users

177

</button>

178

<button onClick={() => refetchExamples.refetchSpecificUser(1)}>

179

Refetch User 1

180

</button>

181

</div>

182

);

183

}

184

```

185

186

### Query Cancellation

187

188

Cancel in-flight queries to prevent unnecessary network requests.

189

190

```typescript { .api }

191

/**

192

* Cancel in-flight queries

193

* @param input - Optional input to target specific queries

194

* @returns Promise that resolves when cancellation is complete

195

*/

196

procedure.cancel(

197

input?: GetQueryProcedureInput<TInput>

198

): Promise<void>;

199

```

200

201

**Usage Examples:**

202

203

```typescript

204

function CancellationExamples() {

205

const utils = trpc.useUtils();

206

207

const cancelExamples = {

208

// Cancel all user queries

209

cancelAllUserQueries: () => utils.user.cancel(),

210

211

// Cancel specific user query

212

cancelSpecificUser: (userId: number) =>

213

utils.user.get.cancel({ id: userId }),

214

215

// Cancel before new operation

216

cancelAndRefetch: async (userId: number) => {

217

await utils.user.get.cancel({ id: userId });

218

await utils.user.get.refetch({ id: userId });

219

},

220

};

221

222

return (

223

<div>

224

<button onClick={cancelExamples.cancelAllUserQueries}>

225

Cancel All User Queries

226

</button>

227

</div>

228

);

229

}

230

```

231

232

### Data Manipulation

233

234

Directly manipulate cached query data without making server requests.

235

236

```typescript { .api }

237

/**

238

* Set query data in the cache

239

* @param input - Input parameters identifying the query

240

* @param updater - Function or value to update the data

241

* @param opts - Set data options

242

*/

243

procedure.setData(

244

input: TInput,

245

updater: Updater<TOutput>,

246

opts?: SetDataOptions

247

): TOutput | undefined;

248

249

/**

250

* Get query data from the cache

251

* @param input - Input parameters identifying the query

252

* @returns Cached data or undefined

253

*/

254

procedure.getData(

255

input?: GetQueryProcedureInput<TInput>

256

): TOutput | undefined;

257

258

type Updater<TData> = TData | ((oldData: TData | undefined) => TData | undefined);

259

260

interface SetDataOptions {

261

updatedAt?: number;

262

}

263

```

264

265

**Usage Examples:**

266

267

```typescript

268

function DataManipulationExamples() {

269

const utils = trpc.useUtils();

270

271

const dataExamples = {

272

// Set user data directly

273

setUserData: (userId: number, userData: User) => {

274

utils.user.get.setData({ id: userId }, userData);

275

},

276

277

// Update user data with function

278

updateUserData: (userId: number, updates: Partial<User>) => {

279

utils.user.get.setData({ id: userId }, (oldData) =>

280

oldData ? { ...oldData, ...updates } : undefined

281

);

282

},

283

284

// Get user data from cache

285

getUserData: (userId: number) => {

286

return utils.user.get.getData({ id: userId });

287

},

288

289

// Optimistic update pattern

290

optimisticUpdate: (userId: number, updates: Partial<User>) => {

291

const previousData = utils.user.get.getData({ id: userId });

292

293

// Apply optimistic update

294

utils.user.get.setData({ id: userId }, (old) =>

295

old ? { ...old, ...updates } : undefined

296

);

297

298

return () => {

299

// Rollback function

300

utils.user.get.setData({ id: userId }, previousData);

301

};

302

},

303

};

304

305

const handleOptimisticUpdate = () => {

306

const rollback = dataExamples.optimisticUpdate(1, { name: "New Name" });

307

308

// Later, if the mutation fails:

309

// rollback();

310

};

311

312

return (

313

<button onClick={handleOptimisticUpdate}>

314

Optimistic Update

315

</button>

316

);

317

}

318

```

319

320

### Infinite Query Utilities

321

322

Specialized utilities for managing infinite/paginated query data.

323

324

```typescript { .api }

325

/**

326

* Set infinite query data in the cache

327

* @param input - Input parameters identifying the infinite query

328

* @param updater - Function or value to update the infinite data

329

* @param opts - Set data options

330

*/

331

procedure.setInfiniteData(

332

input: GetInfiniteQueryInput<TInput>,

333

updater: Updater<InfiniteData<TOutput>>,

334

opts?: SetDataOptions

335

): InfiniteData<TOutput> | undefined;

336

337

/**

338

* Get infinite query data from the cache

339

* @param input - Input parameters identifying the infinite query

340

* @returns Cached infinite data or undefined

341

*/

342

procedure.getInfiniteData(

343

input?: GetInfiniteQueryInput<TInput>

344

): InfiniteData<TOutput> | undefined;

345

```

346

347

**Usage Examples:**

348

349

```typescript

350

function InfiniteQueryExamples() {

351

const utils = trpc.useUtils();

352

353

const infiniteExamples = {

354

// Add new item to infinite list

355

addItemToInfiniteList: (newPost: Post) => {

356

utils.posts.list.setInfiniteData({ limit: 10 }, (oldData) => {

357

if (!oldData) return oldData;

358

359

return {

360

...oldData,

361

pages: [

362

{ ...oldData.pages[0], posts: [newPost, ...oldData.pages[0].posts] },

363

...oldData.pages.slice(1),

364

],

365

};

366

});

367

},

368

369

// Update item in infinite list

370

updateItemInInfiniteList: (postId: number, updates: Partial<Post>) => {

371

utils.posts.list.setInfiniteData({ limit: 10 }, (oldData) => {

372

if (!oldData) return oldData;

373

374

return {

375

...oldData,

376

pages: oldData.pages.map((page) => ({

377

...page,

378

posts: page.posts.map((post) =>

379

post.id === postId ? { ...post, ...updates } : post

380

),

381

})),

382

};

383

});

384

},

385

386

// Get specific item from infinite data

387

getItemFromInfiniteList: (postId: number) => {

388

const data = utils.posts.list.getInfiniteData({ limit: 10 });

389

return data?.pages

390

.flatMap((page) => page.posts)

391

.find((post) => post.id === postId);

392

},

393

};

394

395

return (

396

<button onClick={() => infiniteExamples.addItemToInfiniteList({

397

id: Date.now(),

398

title: "New Post",

399

content: "Post content",

400

})}>

401

Add Post to Infinite List

402

</button>

403

);

404

}

405

```

406

407

### Imperative Fetching

408

409

Fetch data imperatively outside of React components.

410

411

```typescript { .api }

412

/**

413

* Fetch query data imperatively

414

* @param input - Input parameters for the query

415

* @param opts - Fetch options

416

* @returns Promise resolving to the fetched data

417

*/

418

procedure.fetch(

419

input: TInput,

420

opts?: TRPCFetchQueryOptions<TOutput, TError>

421

): Promise<TOutput>;

422

423

/**

424

* Fetch infinite query data imperatively

425

* @param input - Input parameters for the infinite query

426

* @param opts - Fetch infinite options

427

* @returns Promise resolving to the fetched infinite data

428

*/

429

procedure.fetchInfinite(

430

input: GetInfiniteQueryInput<TInput>,

431

opts: TRPCFetchInfiniteQueryOptions<TInput, TOutput, TError>

432

): Promise<InfiniteData<TOutput>>;

433

```

434

435

**Usage Examples:**

436

437

```typescript

438

function ImperativeFetchingExamples() {

439

const utils = trpc.useUtils();

440

441

const fetchExamples = {

442

// Fetch user data imperatively

443

fetchUserData: async (userId: number) => {

444

try {

445

const userData = await utils.user.get.fetch({ id: userId });

446

console.log("Fetched user:", userData);

447

return userData;

448

} catch (error) {

449

console.error("Failed to fetch user:", error);

450

throw error;

451

}

452

},

453

454

// Fetch with options

455

fetchWithOptions: async (userId: number) => {

456

const userData = await utils.user.get.fetch(

457

{ id: userId },

458

{

459

staleTime: 10 * 60 * 1000, // 10 minutes

460

}

461

);

462

return userData;

463

},

464

465

// Fetch infinite data

466

fetchInfiniteData: async () => {

467

const postsData = await utils.posts.list.fetchInfinite(

468

{ limit: 10 },

469

{

470

initialCursor: null,

471

}

472

);

473

return postsData;

474

},

475

};

476

477

const handleImperativeFetch = async () => {

478

const user = await fetchExamples.fetchUserData(1);

479

console.log("User fetched:", user);

480

};

481

482

return (

483

<button onClick={handleImperativeFetch}>

484

Fetch User Imperatively

485

</button>

486

);

487

}

488

```

489

490

### Data Prefetching

491

492

Prefetch data before it's needed to improve user experience.

493

494

```typescript { .api }

495

/**

496

* Prefetch query data

497

* @param input - Input parameters for the query

498

* @param opts - Prefetch options

499

* @returns Promise that resolves when prefetch is complete

500

*/

501

procedure.prefetch(

502

input: TInput,

503

opts?: TRPCFetchQueryOptions<TOutput, TError>

504

): Promise<void>;

505

506

/**

507

* Prefetch infinite query data

508

* @param input - Input parameters for the infinite query

509

* @param opts - Prefetch infinite options

510

* @returns Promise that resolves when prefetch is complete

511

*/

512

procedure.prefetchInfinite(

513

input: GetInfiniteQueryInput<TInput>,

514

opts: TRPCFetchInfiniteQueryOptions<TInput, TOutput, TError>

515

): Promise<void>;

516

```

517

518

**Usage Examples:**

519

520

```typescript

521

function PrefetchingExamples() {

522

const utils = trpc.useUtils();

523

524

const prefetchExamples = {

525

// Prefetch on hover

526

prefetchOnHover: (userId: number) => {

527

utils.user.get.prefetch({ id: userId });

528

},

529

530

// Prefetch related data

531

prefetchRelatedData: async (userId: number) => {

532

await Promise.all([

533

utils.user.get.prefetch({ id: userId }),

534

utils.user.posts.prefetch({ userId }),

535

utils.user.settings.prefetch({ userId }),

536

]);

537

},

538

539

// Prefetch infinite data

540

prefetchInfiniteData: () => {

541

utils.posts.list.prefetchInfinite(

542

{ limit: 10 },

543

{ initialCursor: null }

544

);

545

},

546

};

547

548

return (

549

<div>

550

<button

551

onMouseEnter={() => prefetchExamples.prefetchOnHover(1)}

552

>

553

Hover to Prefetch User 1

554

</button>

555

</div>

556

);

557

}

558

```

559

560

### Data Ensuring

561

562

Ensure data exists in cache, fetching it if necessary.

563

564

```typescript { .api }

565

/**

566

* Ensure query data exists in cache, fetching if necessary

567

* @param input - Input parameters for the query

568

* @param opts - Ensure data options

569

* @returns Promise resolving to the ensured data

570

*/

571

procedure.ensureData(

572

input: TInput,

573

opts?: TRPCFetchQueryOptions<TOutput, TError>

574

): Promise<TOutput>;

575

```

576

577

**Usage Examples:**

578

579

```typescript

580

function DataEnsuringExamples() {

581

const utils = trpc.useUtils();

582

583

const ensureExamples = {

584

// Ensure user data exists before using it

585

ensureUserData: async (userId: number) => {

586

const userData = await utils.user.get.ensureData({ id: userId });

587

// userData is guaranteed to exist

588

return userData;

589

},

590

591

// Ensure data with fresh fetch if stale

592

ensureFreshData: async (userId: number) => {

593

const userData = await utils.user.get.ensureData(

594

{ id: userId },

595

{

596

staleTime: 0, // Always fetch fresh data

597

}

598

);

599

return userData;

600

},

601

};

602

603

const handleEnsureData = async () => {

604

const user = await ensureExamples.ensureUserData(1);

605

console.log("Ensured user data:", user);

606

};

607

608

return (

609

<button onClick={handleEnsureData}>

610

Ensure User Data

611

</button>

612

);

613

}

614

```

615

616

## Common Patterns

617

618

### Cache Management

619

620

```typescript

621

function CacheManagementExample() {

622

const utils = trpc.useUtils();

623

624

const cacheManager = {

625

// Clear all cache

626

clearAll: () => {

627

utils.invalidate();

628

},

629

630

// Clear specific cache

631

clearUserCache: () => {

632

utils.user.invalidate();

633

},

634

635

// Warm cache on app start

636

warmCache: async () => {

637

await Promise.all([

638

utils.user.list.prefetch(),

639

utils.posts.list.prefetch({ limit: 10 }),

640

]);

641

},

642

};

643

644

return (

645

<div>

646

<button onClick={cacheManager.clearAll}>Clear All Cache</button>

647

<button onClick={cacheManager.warmCache}>Warm Cache</button>

648

</div>

649

);

650

}

651

```

652

653

### Optimistic Updates with Rollback

654

655

```typescript

656

function OptimisticUpdatesExample() {

657

const utils = trpc.useUtils();

658

const updateUser = trpc.user.update.useMutation();

659

660

const performOptimisticUpdate = async (userId: number, updates: Partial<User>) => {

661

// Store current data for rollback

662

const previousData = utils.user.get.getData({ id: userId });

663

664

// Apply optimistic update

665

utils.user.get.setData({ id: userId }, (old) =>

666

old ? { ...old, ...updates } : undefined

667

);

668

669

try {

670

// Perform actual mutation

671

await updateUser.mutateAsync({ id: userId, ...updates });

672

} catch (error) {

673

// Rollback on error

674

utils.user.get.setData({ id: userId }, previousData);

675

throw error;

676

}

677

};

678

679

return (

680

<button onClick={() => performOptimisticUpdate(1, { name: "New Name" })}>

681

Update with Optimistic UI

682

</button>

683

);

684

}

685

```