Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

What are Signals?

Slide 3

Slide 3 text

const todos = signal([]);

Slide 4

Slide 4 text

todos = signal([]); todos(); todos.set(...); todos.update((items) => { /* ... */ }); 1 2 3 4 5 6 7

Slide 5

Slide 5 text

todos = signal([]); todos(); todos.set(...); todos.update((items) => { /* ... */ }); 1 2 3 4 5 6 7 todos = signal([]); 1 2 todos(); 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7

Slide 6

Slide 6 text

todos = signal([]); todos(); todos.set(...); todos.update((items) => { /* ... */ }); 1 2 3 4 5 6 7 todos = signal([]); 1 2 todos(); 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7 todos(); todos = signal([]); 1 2 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7

Slide 7

Slide 7 text

todos = signal([]); todos(); todos.set(...); todos.update((items) => { /* ... */ }); 1 2 3 4 5 6 7 todos = signal([]); 1 2 todos(); 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7 todos(); todos = signal([]); 1 2 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7 todos.set(...); todos = signal([]); 1 2 todos(); 3 4 5 6 todos.update((items) => { /* ... */ }); 7

Slide 8

Slide 8 text

todos = signal([]); todos(); todos.set(...); todos.update((items) => { /* ... */ }); 1 2 3 4 5 6 7 todos = signal([]); 1 2 todos(); 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7 todos(); todos = signal([]); 1 2 3 4 todos.set(...); 5 6 todos.update((items) => { /* ... */ }); 7 todos.set(...); todos = signal([]); 1 2 todos(); 3 4 5 6 todos.update((items) => { /* ... */ }); 7 todos.update((items) => { /* ... */ }); todos = signal([]); 1 2 todos(); 3 4 todos.set(...); 5 6 7

Slide 9

Slide 9 text

todos = signal([]); count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); 1 2 3 4 5 6 7

Slide 10

Slide 10 text

todos = signal([]); count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); 1 2 3 4 5 6 7 count = computed(() => todos().length); todos = signal([]); 1 2 3 4 effect(() => { 5 console.log('Todos count changed to ', count()); 6 }); 7

Slide 11

Slide 11 text

todos = signal([]); count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); 1 2 3 4 5 6 7 count = computed(() => todos().length); todos = signal([]); 1 2 3 4 effect(() => { 5 console.log('Todos count changed to ', count()); 6 }); 7 effect(() => { console.log('Todos count changed to ', count()); }); todos = signal([]); 1 2 count = computed(() => todos().length); 3 4 5 6 7

Slide 12

Slide 12 text

todos = signal([]); console.log('Todos: ' + todos()); effect(() => { console.log('Todos', todos()); }); 1 2 3 4 5 6 7

Slide 13

Slide 13 text

todos = signal([]); console.log('Todos: ' + todos()); effect(() => { console.log('Todos', todos()); }); 1 2 3 4 5 6 7 console.log('Todos: ' + todos()); todos = signal([]); 1 2 3 4 effect(() => { 5 console.log('Todos', todos()); 6 }); 7

Slide 14

Slide 14 text

todos = signal([]); console.log('Todos: ' + todos()); effect(() => { console.log('Todos', todos()); }); 1 2 3 4 5 6 7 console.log('Todos: ' + todos()); todos = signal([]); 1 2 3 4 effect(() => { 5 console.log('Todos', todos()); 6 }); 7 effect(() => { console.log('Todos', todos()); }); todos = signal([]); 1 2 console.log('Todos: ' + todos()); 3 4 5 6 7

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

console.log('Todos: ' + todos()); todos = signal([]); 1 2 3 4 effect(() => { 5 console.log('Todos', todos()); 6 }); 7

Slide 17

Slide 17 text

console.log('Todos: ' + todos()); todos = signal([]); 1 2 3 4 effect(() => { 5 console.log('Todos', todos()); 6 }); 7 effect(() => { console.log('Todos', todos()); }); todos = signal([]); 1 2 console.log('Todos: ' + todos()); 3 4 5 6 7

Slide 18

Slide 18 text

Reactivity

Slide 19

Slide 19 text

Reactivity Context base o

Slide 20

Slide 20 text

// Reactive in TS effect(() => { console.log('Todos', todos()); }); // Reactive in HTML
{{ todos() }}
todos = signal([]); 1 2 console.log('Todos: ' + todos()); 3 4 5 6 7 8 9 10 11

Slide 21

Slide 21 text

Live Consumers

Slide 22

Slide 22 text

Consumers

Slide 23

Slide 23 text

Consumers Producers

Slide 24

Slide 24 text

Consumers Producers Or Both!

Slide 25

Slide 25 text

Reactive Graph

Slide 26

Slide 26 text

https://github.com/angular/angular/blob/17.1.2/packages/core/primitives/signals/src/graph.ts#L36-L44

Slide 27

Slide 27 text

todos = signal([]); effect(() => { console.log('Todos', todos()); }); 1 2 3 4 5

Slide 28

Slide 28 text

Signal Reactive Context

Slide 29

Slide 29 text

Signal Reactive Context todos() effect() / HTML

Slide 30

Slide 30 text

Signal todos() Reactive Context effect() / HTML

Slide 31

Slide 31 text

Signal todos() Reactive Context effect() / HTML

Slide 32

Slide 32 text

Push Pull

Slide 33

Slide 33 text

/** * Propagate a dirty notification to live consumers of this producer. */ export function producerNotifyConsumers(node: ReactiveNode): void { if (node.liveConsumerNode === undefined) { return; } // Prevent signal reads when we're updating the graph const prev = inNotificationPhase; inNotificationPhase = true; try { for (const consumer of node.liveConsumerNode) { if (!consumer.dirty) { consumerMarkDirty(consumer); } } } finally { inNotificationPhase = prev; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 34

Slide 34 text

/** * Propagate a dirty notification to live consumers of this producer. */ export function producerNotifyConsumers(node: ReactiveNode): void { if (node.liveConsumerNode === undefined) { return; } // Prevent signal reads when we're updating the graph const prev = inNotificationPhase; inNotificationPhase = true; try { for (const consumer of node.liveConsumerNode) { if (!consumer.dirty) { consumerMarkDirty(consumer); } } } finally { inNotificationPhase = prev; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export function producerNotifyConsumers(node: ReactiveNode): void { /** 1 * Propagate a dirty notification to live consumers of this producer. 2 */ 3 4 if (node.liveConsumerNode === undefined) { 5 return; 6 } 7 8 // Prevent signal reads when we're updating the graph 9 const prev = inNotificationPhase; 10 inNotificationPhase = true; 11 try { 12 for (const consumer of node.liveConsumerNode) { 13 if (!consumer.dirty) { 14 consumerMarkDirty(consumer); 15 } 16 } 17 } finally { 18 inNotificationPhase = prev; 19 } 20 } 21

Slide 35

Slide 35 text

/** * Propagate a dirty notification to live consumers of this producer. */ export function producerNotifyConsumers(node: ReactiveNode): void { if (node.liveConsumerNode === undefined) { return; } // Prevent signal reads when we're updating the graph const prev = inNotificationPhase; inNotificationPhase = true; try { for (const consumer of node.liveConsumerNode) { if (!consumer.dirty) { consumerMarkDirty(consumer); } } } finally { inNotificationPhase = prev; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export function producerNotifyConsumers(node: ReactiveNode): void { /** 1 * Propagate a dirty notification to live consumers of this producer. 2 */ 3 4 if (node.liveConsumerNode === undefined) { 5 return; 6 } 7 8 // Prevent signal reads when we're updating the graph 9 const prev = inNotificationPhase; 10 inNotificationPhase = true; 11 try { 12 for (const consumer of node.liveConsumerNode) { 13 if (!consumer.dirty) { 14 consumerMarkDirty(consumer); 15 } 16 } 17 } finally { 18 inNotificationPhase = prev; 19 } 20 } 21 consumerMarkDirty(consumer); /** 1 * Propagate a dirty notification to live consumers of this producer. 2 */ 3 export function producerNotifyConsumers(node: ReactiveNode): void { 4 if (node.liveConsumerNode === undefined) { 5 return; 6 } 7 8 // Prevent signal reads when we're updating the graph 9 const prev = inNotificationPhase; 10 inNotificationPhase = true; 11 try { 12 for (const consumer of node.liveConsumerNode) { 13 if (!consumer.dirty) { 14 15 } 16 } 17 } finally { 18 inNotificationPhase = prev; 19 } 20 } 21

Slide 36

Slide 36 text

todos = signal([]); effect(() => { console.log('Todos', todos()); }); 1 2 3 4 5

Slide 37

Slide 37 text

todos = signal([]); effect(() => { if(false) { console.log('Todos', todos()); } }); 1 2 3 4 5 6 7

Slide 38

Slide 38 text

Live Consumers

Slide 39

Slide 39 text

count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); todos = signal([]); 1 2 3 4 5 6 7

Slide 40

Slide 40 text

count = computed(() => todos().length); effect(() => { console.log('just a message'); }); todos = signal([]); 1 2 3 4 5 6 7

Slide 41

Slide 41 text

Live Consumers Transitive

Slide 42

Slide 42 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 43

Slide 43 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 44

Slide 44 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 45

Slide 45 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 46

Slide 46 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 47

Slide 47 text

Versioning

Slide 48

Slide 48 text

interface ConsumerNode extends ReactiveNode interface ProducerNode extends ReactiveNode export interface ReactiveNode { version: Version; lastCleanEpoch: Version; dirty: boolean; producerNode: ReactiveNode[] | undefined; producerLastReadVersion: Version[] | undefined; producerIndexOfThis: number[] | undefined; nextProducerIndex: number; liveConsumerNode: ReactiveNode[] | undefined; liveConsumerIndexOfThis: number[] | undefined; consumerAllowSignalWrites: boolean; readonly consumerIsAlwaysLive: boolean; producerMustRecompute(node: unknown): boolean; producerRecomputeValue(node: unknown): void; consumerMarkedDirty(node: unknown): void; consumerOnSignalRead(node: unknown): void; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 49

Slide 49 text

interface ConsumerNode extends ReactiveNode interface ProducerNode extends ReactiveNode export interface ReactiveNode { version: Version; lastCleanEpoch: Version; dirty: boolean; producerNode: ReactiveNode[] | undefined; producerLastReadVersion: Version[] | undefined; producerIndexOfThis: number[] | undefined; nextProducerIndex: number; liveConsumerNode: ReactiveNode[] | undefined; liveConsumerIndexOfThis: number[] | undefined; consumerAllowSignalWrites: boolean; readonly consumerIsAlwaysLive: boolean; producerMustRecompute(node: unknown): boolean; producerRecomputeValue(node: unknown): void; consumerMarkedDirty(node: unknown): void; consumerOnSignalRead(node: unknown): void; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 dirty: boolean; interface ConsumerNode extends ReactiveNode 1 2 interface ProducerNode extends ReactiveNode 3 4 export interface ReactiveNode { 5 version: Version; 6 lastCleanEpoch: Version; 7 8 producerNode: ReactiveNode[] | undefined; 9 producerLastReadVersion: Version[] | undefined; 10 producerIndexOfThis: number[] | undefined; 11 nextProducerIndex: number; 12 liveConsumerNode: ReactiveNode[] | undefined; 13 liveConsumerIndexOfThis: number[] | undefined; 14 consumerAllowSignalWrites: boolean; 15 readonly consumerIsAlwaysLive: boolean; 16 producerMustRecompute(node: unknown): boolean; 17 producerRecomputeValue(node: unknown): void; 18 consumerMarkedDirty(node: unknown): void; 19 consumerOnSignalRead(node: unknown): void; 20 } 21

Slide 50

Slide 50 text

interface ConsumerNode extends ReactiveNode interface ProducerNode extends ReactiveNode export interface ReactiveNode { version: Version; lastCleanEpoch: Version; dirty: boolean; producerNode: ReactiveNode[] | undefined; producerLastReadVersion: Version[] | undefined; producerIndexOfThis: number[] | undefined; nextProducerIndex: number; liveConsumerNode: ReactiveNode[] | undefined; liveConsumerIndexOfThis: number[] | undefined; consumerAllowSignalWrites: boolean; readonly consumerIsAlwaysLive: boolean; producerMustRecompute(node: unknown): boolean; producerRecomputeValue(node: unknown): void; consumerMarkedDirty(node: unknown): void; consumerOnSignalRead(node: unknown): void; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 dirty: boolean; interface ConsumerNode extends ReactiveNode 1 2 interface ProducerNode extends ReactiveNode 3 4 export interface ReactiveNode { 5 version: Version; 6 lastCleanEpoch: Version; 7 8 producerNode: ReactiveNode[] | undefined; 9 producerLastReadVersion: Version[] | undefined; 10 producerIndexOfThis: number[] | undefined; 11 nextProducerIndex: number; 12 liveConsumerNode: ReactiveNode[] | undefined; 13 liveConsumerIndexOfThis: number[] | undefined; 14 consumerAllowSignalWrites: boolean; 15 readonly consumerIsAlwaysLive: boolean; 16 producerMustRecompute(node: unknown): boolean; 17 producerRecomputeValue(node: unknown): void; 18 consumerMarkedDirty(node: unknown): void; 19 consumerOnSignalRead(node: unknown): void; 20 } 21 version: Version; dirty: boolean; interface ConsumerNode extends ReactiveNode 1 2 interface ProducerNode extends ReactiveNode 3 4 export interface ReactiveNode { 5 6 lastCleanEpoch: Version; 7 8 producerNode: ReactiveNode[] | undefined; 9 producerLastReadVersion: Version[] | undefined; 10 producerIndexOfThis: number[] | undefined; 11 nextProducerIndex: number; 12 liveConsumerNode: ReactiveNode[] | undefined; 13 liveConsumerIndexOfThis: number[] | undefined; 14 consumerAllowSignalWrites: boolean; 15 readonly consumerIsAlwaysLive: boolean; 16 producerMustRecompute(node: unknown): boolean; 17 producerRecomputeValue(node: unknown): void; 18 consumerMarkedDirty(node: unknown): void; 19 consumerOnSignalRead(node: unknown): void; 20 } 21

Slide 51

Slide 51 text

export function signalSetFn(node: SignalNode, newValue: T) { if (!producerUpdatesAllowed()) { throwInvalidWriteToSignalError(); } if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } } 1 2 3 4 5 6 7 8 9 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 https://github.com/angular/angular/blob/1872fcd8e09fefb52f9b36e8261702cd6fb03f85/packages/core/primitives/signals/src/signal.ts

Slide 52

Slide 52 text

export function signalSetFn(node: SignalNode, newValue: T) { if (!producerUpdatesAllowed()) { throwInvalidWriteToSignalError(); } if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } } 1 2 3 4 5 6 7 8 9 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 function signalValueChanged(node: SignalNode): void { node.version++; producerIncrementEpoch(); producerNotifyConsumers(node); postSignalSetFn?.(); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 signalValueChanged(node); 8 } 9 } 10 11 // ... 12 13 14 15 16 17 18 19 https://github.com/angular/angular/blob/1872fcd8e09fefb52f9b36e8261702cd6fb03f85/packages/core/primitives/signals/src/signal.ts

Slide 53

Slide 53 text

export function signalSetFn(node: SignalNode, newValue: T) { if (!producerUpdatesAllowed()) { throwInvalidWriteToSignalError(); } if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } } 1 2 3 4 5 6 7 8 9 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 function signalValueChanged(node: SignalNode): void { node.version++; producerIncrementEpoch(); producerNotifyConsumers(node); postSignalSetFn?.(); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 signalValueChanged(node); 8 } 9 } 10 11 // ... 12 13 14 15 16 17 18 19 if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 6 7 8 9 } 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 https://github.com/angular/angular/blob/1872fcd8e09fefb52f9b36e8261702cd6fb03f85/packages/core/primitives/signals/src/signal.ts

Slide 54

Slide 54 text

export function signalSetFn(node: SignalNode, newValue: T) { if (!producerUpdatesAllowed()) { throwInvalidWriteToSignalError(); } if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } } 1 2 3 4 5 6 7 8 9 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 function signalValueChanged(node: SignalNode): void { node.version++; producerIncrementEpoch(); producerNotifyConsumers(node); postSignalSetFn?.(); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 signalValueChanged(node); 8 } 9 } 10 11 // ... 12 13 14 15 16 17 18 19 if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 6 7 8 9 } 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 signalValueChanged(node); function signalValueChanged(node: SignalNode): void { node.version++; producerIncrementEpoch(); producerNotifyConsumers(node); postSignalSetFn?.(); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 8 } 9 } 10 11 // ... 12 13 14 15 16 17 18 19 https://github.com/angular/angular/blob/1872fcd8e09fefb52f9b36e8261702cd6fb03f85/packages/core/primitives/signals/src/signal.ts

Slide 55

Slide 55 text

export function signalSetFn(node: SignalNode, newValue: T) { if (!producerUpdatesAllowed()) { throwInvalidWriteToSignalError(); } if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } } 1 2 3 4 5 6 7 8 9 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 function signalValueChanged(node: SignalNode): void { node.version++; producerIncrementEpoch(); producerNotifyConsumers(node); postSignalSetFn?.(); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 signalValueChanged(node); 8 } 9 } 10 11 // ... 12 13 14 15 16 17 18 19 if (!node.equal(node.value, newValue)) { node.value = newValue; signalValueChanged(node); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 6 7 8 9 } 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 node.version++; 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 signalValueChanged(node); function signalValueChanged(node: SignalNode): void { node.version++; producerIncrementEpoch(); producerNotifyConsumers(node); postSignalSetFn?.(); } export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 8 } 9 } 10 11 // ... 12 13 14 15 16 17 18 19 signalValueChanged(node); node.version++; export function signalSetFn(node: SignalNode, newValue: T) { 1 if (!producerUpdatesAllowed()) { 2 throwInvalidWriteToSignalError(); 3 } 4 5 if (!node.equal(node.value, newValue)) { 6 node.value = newValue; 7 8 } 9 } 10 11 // ... 12 13 function signalValueChanged(node: SignalNode): void { 14 15 producerIncrementEpoch(); 16 producerNotifyConsumers(node); 17 postSignalSetFn?.(); 18 } 19 https://github.com/angular/angular/blob/1872fcd8e09fefb52f9b36e8261702cd6fb03f85/packages/core/primitives/signals/src/signal.ts

Slide 56

Slide 56 text

todos = signal([]); count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); todos.update((items) => [...items, { ... }]); // CHANGE 1 2 3 4 5 6 7 8 9

Slide 57

Slide 57 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 58

Slide 58 text

Signal todos() Reactive Context effect() / HTML computed() dirty

Slide 59

Slide 59 text

Signal todos() Reactive Context effect() / HTML computed() dirty dirty

Slide 60

Slide 60 text

Signal todos() Reactive Context effect() / HTML computed() dirty dirty ask

Slide 61

Slide 61 text

Signal todos() Reactive Context effect() / HTML computed() dirty dirty ask ask

Slide 62

Slide 62 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 63

Slide 63 text

Signal todos() Reactive Context effect() / HTML computed() version++

Slide 64

Slide 64 text

Signal todos() Reactive Context effect() / HTML computed() version++

Slide 65

Slide 65 text

Signal todos() Reactive Context effect() / HTML computed() version++ pull value

Slide 66

Slide 66 text

Signal todos() Reactive Context effect() / HTML computed() version++ pull value version++

Slide 67

Slide 67 text

Signal todos() Reactive Context effect() / HTML computed() version++ pull value version++

Slide 68

Slide 68 text

Signal todos() Reactive Context effect() / HTML computed() version++ pull value version++ pull value

Slide 69

Slide 69 text

todos = signal([]); count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); todos.update((items) => [...items]); // "NO" CHANGE 1 2 3 4 5 6 7 8 9

Slide 70

Slide 70 text

todos = signal([]); count = computed(() => todos().length); effect(() => { console.log('Todos count changed to ', count()); }); todos.update((items) => [...items]); // "NO" CHANGE 1 2 3 4 5 6 7 8 9 todos.update((items) => [...items]); // "NO" CHANGE todos = signal([]); 1 2 count = computed(() => todos().length); 3 4 effect(() => { 5 console.log('Todos count changed to ', count()); 6 }); 7 8 9

Slide 71

Slide 71 text

todos.update((items) => [...items]); // Only ref change todos = signal([]); 1 2 count = computed(() => todos().length); 3 4 effect(() => { 5 console.log('Todos count changed to ', count()); 6 }); 7 8 9 export function defaultEquals(a: T, b: T) { return Object.is(a, b); } 1 2 3 https://github.com/angular/angular/blob/23eafb4aa20f45233b22a62fe032e47ac21eca20/packages/core/primitives/signals/src/equality.ts#L17

Slide 72

Slide 72 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 73

Slide 73 text

Signal todos() Reactive Context effect() / HTML computed() dirty

Slide 74

Slide 74 text

Signal todos() Reactive Context effect() / HTML computed() dirty dirty

Slide 75

Slide 75 text

Signal todos() Reactive Context effect() / HTML computed() dirty dirty ask

Slide 76

Slide 76 text

Signal todos() Reactive Context effect() / HTML computed() dirty dirty ask ask

Slide 77

Slide 77 text

Signal todos() Reactive Context effect() / HTML computed()

Slide 78

Slide 78 text

Signal todos() Reactive Context effect() / HTML computed() version++

Slide 79

Slide 79 text

Signal todos() Reactive Context effect() / HTML computed() version++

Slide 80

Slide 80 text

Signal todos() Reactive Context effect() / HTML computed() version++ pull value

Slide 81

Slide 81 text

Signal todos() Reactive Context effect() / HTML computed() Same length! version++ pull value

Slide 82

Slide 82 text

Dependency Tracking Dynamic

Slide 83

Slide 83 text

computed(() => isEven() ? getDoneLength() : getUndoneLength() ); 1 2 3 4

Slide 84

Slide 84 text

computed(() => isEven() ? getDoneLength() : getUndoneLength() ); 1 2 3 4 [isEven, getDoneLength] [isEven, getUndoneLength] 1 2 3 [isEven, getDoneLength] 1 2 [isEven, getUndoneLength] 3

Slide 85

Slide 85 text

computed(() => isEven() ? getDoneLength() : getUndoneLength() ); 1 2 3 4 [isEven, getDoneLength] [isEven, getUndoneLength] 1 2 3 [isEven, getDoneLength] 1 2 [isEven, getUndoneLength] 3 [isEven, getUndoneLength] [isEven, getDoneLength] 1 2 3

Slide 86

Slide 86 text

Fabian

Slide 87

Slide 87 text

Fabian Google Developer Expert Microsoft MVP Pluralsight Author

Slide 88

Slide 88 text

No content

Slide 89

Slide 89 text

No content