or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-resolution.mdbuiltin-components.mdcomponents.mdcomposition-helpers.mddependency-injection.mderror-handling.mdhydration.mdindex.mdinternal-render-helpers.mdlifecycle.mdreactivity.mdscheduler-timing.mdssr-context.mdvdom-rendering.mdwatch-effects.md

reactivity.mddocs/

0

# Reactivity System

1

2

Vue's reactivity system provides fine-grained reactive data structures with automatic dependency tracking. The system enables efficient updates by tracking which computations depend on which reactive data.

3

4

## Capabilities

5

6

### Reactive State Creation

7

8

Create reactive proxies that automatically track dependencies and trigger updates.

9

10

```typescript { .api }

11

/**

12

* Creates a reactive proxy of an object

13

* @param target - Object to make reactive

14

* @returns Reactive proxy of the target object

15

*/

16

function reactive<T extends object>(target: T): T;

17

18

/**

19

* Creates a reactive reference wrapper for primitive values

20

* @param value - Initial value to wrap

21

* @returns Reactive reference object

22

*/

23

function ref<T>(value: T): Ref<T>;

24

25

/**

26

* Creates a read-only proxy that prevents modifications

27

* @param target - Object to make read-only

28

* @returns Read-only proxy of the target

29

*/

30

function readonly<T>(target: T): DeepReadonly<T>;

31

32

/**

33

* Creates a shallow reactive reference that only tracks .value changes

34

* @param value - Initial value

35

* @returns Shallow reactive reference

36

*/

37

function shallowRef<T>(value: T): ShallowRef<T>;

38

39

/**

40

* Creates a shallow reactive proxy that only tracks first-level properties

41

* @param target - Object to make shallow reactive

42

* @returns Shallow reactive proxy

43

*/

44

function shallowReactive<T extends object>(target: T): ShallowReactive<T>;

45

46

/**

47

* Creates a shallow read-only proxy

48

* @param target - Object to make shallow read-only

49

* @returns Shallow read-only proxy

50

*/

51

function shallowReadonly<T extends object>(target: T): Readonly<T>;

52

53

/**

54

* Creates a custom ref with explicit dependency tracking control

55

* @param factory - Factory function that returns get/set functions

56

* @returns Custom reactive reference

57

*/

58

function customRef<T>(factory: CustomRefFactory<T>): Ref<T>;

59

```

60

61

**Usage Examples:**

62

63

```typescript

64

import { reactive, ref, readonly, shallowRef } from "@vue/runtime-core";

65

66

// Reactive object

67

const state = reactive({

68

count: 0,

69

user: { name: "Alice", age: 25 }

70

});

71

72

// Reactive primitive

73

const count = ref(0);

74

count.value = 5; // Triggers reactivity

75

76

// Read-only state

77

const readonlyState = readonly(state);

78

// readonlyState.count = 10; // Error in TypeScript, ignored in runtime

79

80

// Shallow ref for complex objects

81

const complexData = shallowRef({ deep: { nested: { value: 1 } } });

82

complexData.value = { deep: { nested: { value: 2 } } }; // Triggers reactivity

83

complexData.value.deep.nested.value = 3; // Does NOT trigger reactivity

84

85

// Custom ref with debounced updates

86

function useDebouncedRef(value: string, delay = 200) {

87

let timeout: NodeJS.Timeout;

88

return customRef((track, trigger) => ({

89

get() {

90

track();

91

return value;

92

},

93

set(newValue) {

94

clearTimeout(timeout);

95

timeout = setTimeout(() => {

96

value = newValue;

97

trigger();

98

}, delay);

99

}

100

}));

101

}

102

```

103

104

### Reactivity Utilities

105

106

Utility functions for working with reactive data and references.

107

108

```typescript { .api }

109

/**

110

* Returns the inner value if it's a ref, otherwise returns the value itself

111

* @param ref - Value that may or may not be a ref

112

* @returns Unwrapped value

113

*/

114

function unref<T>(ref: MaybeRef<T>): T;

115

116

/**

117

* Creates a ref for a property on a reactive object

118

* @param object - Reactive object

119

* @param key - Property key

120

* @returns Ref linked to the object property

121

*/

122

function toRef<T extends object, K extends keyof T>(object: T, key: K): ToRef<T[K]>;

123

124

/**

125

* Converts all properties of a reactive object to refs

126

* @param object - Reactive object to convert

127

* @returns Object with all properties as refs

128

*/

129

function toRefs<T extends object>(object: T): ToRefs<T>;

130

131

/**

132

* Returns the value of value/ref/getter

133

* @param val - Value, ref, or getter function

134

* @returns Resolved value

135

*/

136

function toValue<T>(val: MaybeRefOrGetter<T>): T;

137

138

/**

139

* Proxies an object to auto-unwrap refs in properties

140

* @param objectWithRefs - Object containing refs

141

* @returns Proxy that auto-unwraps refs

142

*/

143

function proxyRefs<T extends object>(objectWithRefs: T): T;

144

145

/**

146

* Checks if a value is a ref

147

* @param val - Value to check

148

* @returns True if value is a ref

149

*/

150

function isRef<T>(val: Ref<T> | unknown): val is Ref<T>;

151

152

/**

153

* Checks if a value is a reactive proxy

154

* @param val - Value to check

155

* @returns True if value is reactive

156

*/

157

function isProxy(val: unknown): boolean;

158

159

/**

160

* Checks if a value is reactive (not readonly)

161

* @param val - Value to check

162

* @returns True if value is reactive

163

*/

164

function isReactive(val: unknown): boolean;

165

166

/**

167

* Checks if a value is readonly

168

* @param val - Value to check

169

* @returns True if value is readonly

170

*/

171

function isReadonly(val: unknown): boolean;

172

173

/**

174

* Checks if a value is shallow

175

* @param val - Value to check

176

* @returns True if value is shallow

177

*/

178

function isShallow(val: unknown): boolean;

179

180

/**

181

* Marks an object to never be converted to a proxy

182

* @param value - Object to mark as raw

183

* @returns The same object, marked as raw

184

*/

185

function markRaw<T extends object>(value: T): T;

186

187

/**

188

* Returns the raw, original object of a reactive proxy

189

* @param observed - Reactive proxy

190

* @returns Original object

191

*/

192

function toRaw<T>(observed: T): T;

193

194

/**

195

* Manually triggers effects for a shallow ref

196

* @param ref - Shallow ref to trigger

197

*/

198

function triggerRef(ref: ShallowRef): void;

199

```

200

201

**Usage Examples:**

202

203

```typescript

204

import { reactive, ref, toRefs, toRef, unref, isRef } from "@vue/runtime-core";

205

206

const state = reactive({ count: 0, name: "Vue" });

207

208

// Convert object properties to refs

209

const { count, name } = toRefs(state);

210

console.log(count.value); // 0

211

212

// Create ref for single property

213

const countRef = toRef(state, 'count');

214

countRef.value = 5; // Updates state.count

215

216

// Unwrap refs safely

217

function processValue(maybeRef: MaybeRef<number>) {

218

const value = unref(maybeRef);

219

return value * 2;

220

}

221

222

processValue(ref(5)); // 10

223

processValue(10); // 20

224

225

// Check if value is ref

226

if (isRef(count)) {

227

console.log("count is a ref:", count.value);

228

}

229

```

230

231

### Computed Properties

232

233

Create computed values that automatically update when their dependencies change.

234

235

```typescript { .api }

236

/**

237

* Creates a computed ref with getter only

238

* @param getter - Function that returns computed value

239

* @returns Read-only computed ref

240

*/

241

function computed<T>(getter: () => T): ComputedRef<T>;

242

243

/**

244

* Creates a computed ref with getter and setter

245

* @param options - Object with get and set functions

246

* @returns Writable computed ref

247

*/

248

function computed<T>(options: WritableComputedOptions<T>): WritableComputedRef<T>;

249

250

interface WritableComputedOptions<T> {

251

get: () => T;

252

set: (value: T) => void;

253

}

254

```

255

256

**Usage Examples:**

257

258

```typescript

259

import { ref, computed } from "@vue/runtime-core";

260

261

const count = ref(0);

262

263

// Read-only computed

264

const doubled = computed(() => count.value * 2);

265

console.log(doubled.value); // 0

266

count.value = 5;

267

console.log(doubled.value); // 10

268

269

// Writable computed

270

const fullName = ref("");

271

const firstName = ref("John");

272

const lastName = ref("Doe");

273

274

const computedFullName = computed({

275

get: () => `${firstName.value} ${lastName.value}`,

276

set: (value) => {

277

const parts = value.split(' ');

278

firstName.value = parts[0] || '';

279

lastName.value = parts[1] || '';

280

}

281

});

282

283

console.log(computedFullName.value); // "John Doe"

284

computedFullName.value = "Jane Smith";

285

console.log(firstName.value); // "Jane"

286

console.log(lastName.value); // "Smith"

287

```

288

289

### Effect System

290

291

Create and manage reactive effects with fine-grained control over execution.

292

293

```typescript { .api }

294

/**

295

* Creates a reactive effect that runs when dependencies change

296

* @param fn - Effect function to run

297

* @param options - Optional effect configuration

298

* @returns Effect runner function

299

*/

300

function effect(fn: () => void, options?: ReactiveEffectOptions): ReactiveEffectRunner;

301

302

/**

303

* Stops a reactive effect from running

304

* @param runner - Effect runner to stop

305

*/

306

function stop(runner: ReactiveEffectRunner): void;

307

308

/**

309

* Gets the currently running watcher/effect

310

* @returns Current reactive effect or undefined

311

*/

312

function getCurrentWatcher(): ReactiveEffect | undefined;

313

314

/**

315

* Registers a cleanup function for the current watcher

316

* @param fn - Cleanup function to register

317

*/

318

function onWatcherCleanup(fn: () => void): void;

319

320

interface ReactiveEffectOptions {

321

scheduler?: EffectScheduler;

322

scope?: EffectScope;

323

allowRecurse?: boolean;

324

onStop?: () => void;

325

}

326

327

interface ReactiveEffectRunner<T = any> {

328

(): T;

329

effect: ReactiveEffect;

330

}

331

```

332

333

**Usage Examples:**

334

335

```typescript

336

import { ref, effect, stop } from "@vue/runtime-core";

337

338

const count = ref(0);

339

const name = ref("Vue");

340

341

// Basic effect

342

const runner = effect(() => {

343

console.log(`Count is: ${count.value}`);

344

});

345

346

count.value = 1; // Logs: "Count is: 1"

347

348

// Effect with scheduler

349

const scheduledRunner = effect(

350

() => {

351

console.log(`Scheduled: ${name.value}`);

352

},

353

{

354

scheduler: (job) => {

355

// Custom scheduling logic

356

setTimeout(job, 100);

357

}

358

}

359

);

360

361

// Stop an effect

362

stop(runner);

363

count.value = 2; // No longer logs

364

```

365

366

### Effect Scope

367

368

Manage groups of effects with automatic cleanup.

369

370

```typescript { .api }

371

/**

372

* Creates an effect scope for managing multiple effects

373

* @param detached - Whether the scope is detached from parent

374

* @returns New effect scope

375

*/

376

function effectScope(detached?: boolean): EffectScope;

377

378

/**

379

* Gets the current active effect scope

380

* @returns Current effect scope or undefined

381

*/

382

function getCurrentScope(): EffectScope | undefined;

383

384

/**

385

* Registers a dispose callback for the current scope

386

* @param fn - Callback to run when scope is disposed

387

*/

388

function onScopeDispose(fn: () => void): void;

389

390

interface EffectScope {

391

run<T>(fn: () => T): T | undefined;

392

stop(): void;

393

}

394

```

395

396

**Usage Examples:**

397

398

```typescript

399

import { ref, effect, effectScope, onScopeDispose } from "@vue/runtime-core";

400

401

const count = ref(0);

402

403

// Create a scope

404

const scope = effectScope();

405

406

scope.run(() => {

407

// Effects created in this scope will be collected

408

effect(() => {

409

console.log(`Count: ${count.value}`);

410

});

411

412

effect(() => {

413

console.log(`Count doubled: ${count.value * 2}`);

414

});

415

416

// Cleanup when scope is disposed

417

onScopeDispose(() => {

418

console.log("Scope disposed");

419

});

420

});

421

422

count.value = 1; // Both effects run

423

424

// Stop all effects in scope

425

scope.stop(); // Logs: "Scope disposed"

426

count.value = 2; // No effects run

427

```

428

429

## Types

430

431

```typescript { .api }

432

interface Ref<T> {

433

value: T;

434

}

435

436

interface ShallowRef<T> extends Ref<T> {

437

/**

438

* Type differentiator only.

439

* We need this to be in public d.ts but don't want it to show up in IDE

440

* autocomplete, so we use a private Symbol instead.

441

*/

442

[ShallowRefMarker]?: true;

443

}

444

445

interface ComputedRef<T> extends WritableComputedRef<T> {

446

readonly value: T;

447

}

448

449

interface WritableComputedRef<T> extends Ref<T> {

450

readonly effect: ReactiveEffect<T>;

451

}

452

453

type MaybeRef<T> = T | Ref<T>;

454

type MaybeRefOrGetter<T> = T | Ref<T> | (() => T);

455

456

type ToRef<T> = T extends Ref ? T : Ref<T>;

457

458

type ToRefs<T> = {

459

[K in keyof T]: ToRef<T[K]>;

460

};

461

462

type UnwrapRef<T> = T extends ShallowRef<infer V>

463

? V

464

: T extends Ref<infer V>

465

? UnwrapRefSimple<V>

466

: UnwrapRefSimple<T>;

467

468

interface CustomRefFactory<T> {

469

(track: () => void, trigger: () => void): {

470

get: () => T;

471

set: (value: T) => void;

472

};

473

}

474

475

interface ReactiveEffect<T = any> {

476

(): T;

477

_isEffect: true;

478

id: number;

479

active: boolean;

480

raw: () => T;

481

deps: Array<Dep>;

482

options: ReactiveEffectOptions;

483

allowRecurse: boolean;

484

}

485

486

type EffectScheduler = (fn: () => void) => void;

487

488

interface EffectScope {

489

detached: boolean;

490

parent: EffectScope | undefined;

491

scopes: EffectScope[] | undefined;

492

effects: ReactiveEffect[] | undefined;

493

cleanups: (() => void)[] | undefined;

494

495

run<T>(fn: () => T): T | undefined;

496

on(): void;

497

off(): void;

498

stop(fromParent?: boolean): void;

499

}

500

```