or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdcomponent-extension.mdhooks.mdindex.mdjsx-elements.mdroot-creation.md

hooks.mddocs/

0

# React Hooks

1

2

@pixi/react provides React hooks for accessing PixiJS application state, integrating with the ticker system, and dynamically extending components. These hooks follow React patterns and integrate seamlessly with component lifecycle.

3

4

## Capabilities

5

6

### useApplication Hook

7

8

Retrieves the nearest PixiJS Application from the React context.

9

10

```typescript { .api }

11

/**

12

* Retrieves the nearest Pixi.js Application from the Pixi React context

13

* @returns ApplicationState containing the app instance and initialization status

14

* @throws Error if used outside of Application component context

15

*/

16

function useApplication(): ApplicationState;

17

18

interface ApplicationState {

19

/** The PixiJS Application instance */

20

app: PixiApplication;

21

/** Whether the application has finished initialization */

22

isInitialised: boolean;

23

/** Whether the application is currently initializing */

24

isInitialising: boolean;

25

}

26

```

27

28

**Usage Examples:**

29

30

```typescript

31

import { useApplication } from "@pixi/react";

32

import { useEffect, useState } from "react";

33

34

const AppInfoComponent = () => {

35

const { app, isInitialised } = useApplication();

36

const [fps, setFps] = useState(0);

37

38

useEffect(() => {

39

if (!isInitialised) return;

40

41

// Access application properties

42

console.log("Canvas size:", app.canvas.width, app.canvas.height);

43

console.log("Renderer type:", app.renderer.type);

44

45

// Monitor FPS

46

const updateFPS = () => setFps(app.ticker.FPS);

47

app.ticker.add(updateFPS);

48

49

return () => app.ticker.remove(updateFPS);

50

}, [app, isInitialised]);

51

52

if (!isInitialised) {

53

return <pixiText text="Loading..." />;

54

}

55

56

return (

57

<pixiText

58

text={`FPS: ${fps.toFixed(1)}`}

59

x={10}

60

y={10}

61

style={{ fontSize: 14, fill: "white" }}

62

/>

63

);

64

};

65

66

// Access renderer information

67

const RendererInfo = () => {

68

const { app, isInitialised } = useApplication();

69

70

if (!isInitialised) return null;

71

72

const rendererInfo = {

73

type: app.renderer.type,

74

resolution: app.renderer.resolution,

75

backgroundColor: app.renderer.background.color,

76

};

77

78

return (

79

<pixiText

80

text={`Renderer: ${rendererInfo.type}`}

81

x={10}

82

y={30}

83

/>

84

);

85

};

86

```

87

88

### useTick Hook

89

90

Attaches a callback to the application's Ticker for frame-based animations and updates.

91

92

```typescript { .api }

93

/**

94

* Attaches a callback to the application's Ticker

95

* @param options - Either a callback function or options object with callback

96

*/

97

function useTick<T>(options: TickerCallback<T> | UseTickOptions<T>): void;

98

99

type TickerCallback<T> = (ticker: Ticker, context?: T) => void;

100

101

interface UseTickOptions<T> {

102

/** The function to be called on each tick */

103

callback: TickerCallback<T>;

104

/** The value of `this` within the callback */

105

context?: T;

106

/** Whether this callback is currently enabled */

107

isEnabled?: boolean;

108

/** The priority of this callback compared to other callbacks on the ticker */

109

priority?: number;

110

}

111

```

112

113

**Usage Examples:**

114

115

```typescript

116

import { useTick } from "@pixi/react";

117

import { useState, useCallback } from "react";

118

119

// Simple animation with function callback

120

const RotatingSprite = ({ texture }) => {

121

const [rotation, setRotation] = useState(0);

122

123

useTick(useCallback((ticker) => {

124

setRotation(prev => prev + 0.01 * ticker.deltaTime);

125

}, []));

126

127

return (

128

<pixiSprite

129

texture={texture}

130

rotation={rotation}

131

anchor={0.5}

132

x={400}

133

y={300}

134

/>

135

);

136

};

137

138

// Advanced animation with options

139

const AnimatedGraphics = () => {

140

const [scale, setScale] = useState(1);

141

const [isAnimating, setIsAnimating] = useState(true);

142

143

useTick({

144

callback: useCallback((ticker) => {

145

setScale(prev => {

146

const newScale = prev + Math.sin(ticker.lastTime * 0.01) * 0.001;

147

return Math.max(0.5, Math.min(2, newScale));

148

});

149

}, []),

150

isEnabled: isAnimating,

151

priority: 1, // Higher priority than default (0)

152

});

153

154

const drawCallback = useCallback((graphics) => {

155

graphics.clear();

156

graphics.setFillStyle({ color: "blue" });

157

graphics.circle(0, 0, 50);

158

graphics.fill();

159

}, []);

160

161

return (

162

<pixiContainer>

163

<pixiGraphics

164

draw={drawCallback}

165

scale={scale}

166

anchor={0.5}

167

x={200}

168

y={200}

169

/>

170

<pixiText

171

text={isAnimating ? "Click to pause" : "Click to resume"}

172

interactive

173

onPointerTap={() => setIsAnimating(!isAnimating)}

174

x={10}

175

y={10}

176

/>

177

</pixiContainer>

178

);

179

};

180

181

// Context-based animation

182

class AnimationContext {

183

constructor(public speed: number = 1) {}

184

185

updateRotation(rotation: number, ticker: Ticker): number {

186

return rotation + 0.02 * this.speed * ticker.deltaTime;

187

}

188

}

189

190

const ContextAnimation = () => {

191

const [rotation, setRotation] = useState(0);

192

const [context] = useState(() => new AnimationContext(2));

193

194

useTick({

195

callback: function(ticker) {

196

// `this` refers to the context object

197

setRotation(prev => this.updateRotation(prev, ticker));

198

},

199

context,

200

});

201

202

return (

203

<pixiSprite

204

texture={texture}

205

rotation={rotation}

206

anchor={0.5}

207

/>

208

);

209

};

210

```

211

212

### useExtend Hook

213

214

Hook version of the extend function for dynamically exposing PixiJS components.

215

216

```typescript { .api }

217

/**

218

* Hook version of extend function for exposing Pixi.js components

219

* @param objects - Object mapping component names to PixiJS constructor classes

220

*/

221

function useExtend(objects: Parameters<typeof extend>[0]): void;

222

```

223

224

**Usage Examples:**

225

226

```typescript

227

import { useExtend } from "@pixi/react";

228

import { useMemo, useState, useEffect } from "react";

229

230

// Dynamic component loading

231

const DynamicComponentLoader = ({ enableAdvanced }) => {

232

const [advancedComponents, setAdvancedComponents] = useState(null);

233

234

useEffect(() => {

235

if (enableAdvanced) {

236

import("pixi.js").then(({ NineSlicePlane, SimplePlane, TilingSprite }) => {

237

setAdvancedComponents({ NineSlicePlane, SimplePlane, TilingSprite });

238

});

239

}

240

}, [enableAdvanced]);

241

242

// Extend components when they become available

243

useExtend(advancedComponents || {});

244

245

if (!enableAdvanced || !advancedComponents) {

246

return <pixiText text="Basic mode" />;

247

}

248

249

return (

250

<pixiContainer>

251

<pixiTilingSprite

252

texture={texture}

253

width={200}

254

height={200}

255

/>

256

<pixiNineSlicePlane

257

texture={buttonTexture}

258

leftWidth={10}

259

rightWidth={10}

260

topHeight={10}

261

bottomHeight={10}

262

/>

263

</pixiContainer>

264

);

265

};

266

267

// Conditional extension based on props

268

const ConditionalExtender = ({ includeFilters, includeMesh }) => {

269

const components = useMemo(() => {

270

const result = {};

271

272

if (includeFilters) {

273

import("pixi.js").then(({ BlurFilter, ColorMatrixFilter }) => {

274

Object.assign(result, { BlurFilter, ColorMatrixFilter });

275

});

276

}

277

278

if (includeMesh) {

279

import("pixi.js").then(({ Mesh, PlaneGeometry }) => {

280

Object.assign(result, { Mesh, PlaneGeometry });

281

});

282

}

283

284

return result;

285

}, [includeFilters, includeMesh]);

286

287

useExtend(components);

288

289

return (

290

<pixiContainer>

291

{includeFilters && (

292

<pixiText text="Filters available" />

293

)}

294

{includeMesh && (

295

<pixiText text="Mesh components available" y={20} />

296

)}

297

</pixiContainer>

298

);

299

};

300

301

// Plugin integration with hooks

302

const PluginIntegration = () => {

303

const [pluginComponents, setPluginComponents] = useState({});

304

305

useEffect(() => {

306

// Dynamically load plugin components

307

Promise.all([

308

import("pixi-spine").then(m => ({ Spine: m.Spine })),

309

import("pixi-viewport").then(m => ({ Viewport: m.Viewport })),

310

]).then(([spine, viewport]) => {

311

setPluginComponents({ ...spine, ...viewport });

312

});

313

}, []);

314

315

useExtend(pluginComponents);

316

317

const hasSpine = 'Spine' in pluginComponents;

318

const hasViewport = 'Viewport' in pluginComponents;

319

320

return (

321

<pixiContainer>

322

{hasViewport && hasSpine && (

323

<pixiViewport

324

screenWidth={800}

325

screenHeight={600}

326

worldWidth={1200}

327

worldHeight={900}

328

>

329

<pixiSpine spineData={spineData} />

330

</pixiViewport>

331

)}

332

</pixiContainer>

333

);

334

};

335

```

336

337

## Hook Rules and Best Practices

338

339

### Dependency Management

340

341

```typescript

342

// ✓ Stable callback reference

343

const RotatingSprite = () => {

344

const [rotation, setRotation] = useState(0);

345

346

const tickCallback = useCallback((ticker) => {

347

setRotation(prev => prev + 0.01 * ticker.deltaTime);

348

}, []); // Empty dependencies - callback is stable

349

350

useTick(tickCallback);

351

352

return <pixiSprite rotation={rotation} />;

353

};

354

355

// ✗ Avoid recreating callback on every render

356

const BadExample = () => {

357

const [rotation, setRotation] = useState(0);

358

359

// This creates a new function on every render!

360

useTick((ticker) => {

361

setRotation(prev => prev + 0.01 * ticker.deltaTime);

362

});

363

364

return <pixiSprite rotation={rotation} />;

365

};

366

```

367

368

### Conditional Hook Usage

369

370

```typescript

371

// ✓ Use isEnabled option for conditional ticking

372

const ConditionalAnimation = ({ shouldAnimate }) => {

373

useTick({

374

callback: useCallback((ticker) => {

375

// Animation logic

376

}, []),

377

isEnabled: shouldAnimate, // Control via options

378

});

379

380

return <pixiSprite />;

381

};

382

383

// ✗ Don't conditionally call hooks

384

const BadConditional = ({ shouldAnimate }) => {

385

if (shouldAnimate) {

386

useTick(() => {}); // Violates rules of hooks!

387

}

388

389

return <pixiSprite />;

390

};

391

```

392

393

## Error Handling

394

395

The hooks include comprehensive error handling:

396

397

- **useApplication**: Throws meaningful error if used outside Application context

398

- **useTick**: Validates callback function and handles ticker lifecycle

399

- **useExtend**: Validates component objects and handles registration failures

400

- All hooks properly clean up resources during component unmounting