← Back to Articles         
Angular Signals: set(), update(), computed(), effect()

Angular Signals: set(), update(), computed(), effect()

Published on 01 Oct 2026     10 min read Angular
Angular Signals

Angular Signals: set(), update(), computed(), effect() and linkedSignal()

These APIs have different responsibilities:

signal()       → Store reactive state
set/update     → Change signal state
computed()     → Derive read-only state
effect()       → Run side effects when dependencies change
linkedSignal() → Writable state linked to other reactive state

1. How do you read and update a Signal?

What is it?

After creating a signal:

count = signal(0);

you can:

  • Read it using count()
  • Set a new value using count.set(...)
  • Update it based on the current value using count.update(...)

Full Simple Program

counter.ts

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  templateUrl: './counter.html'
})
export class Counter {

  count = signal(0);

  increment() {
    this.count.update(value => value + 1);
  }

  decrement() {
    this.count.update(value => value - 1);
  }

  setHundred() {
    this.count.set(100);
  }

  reset() {
    this.count.set(0);
  }
}

counter.html

<h2>Count: {{ count() }}</h2>

<button (click)="increment()">+</button>
<button (click)="decrement()">-</button>
<button (click)="setHundred()">Set 100</button>
<button (click)="reset()">Reset</button>

Reading a Signal

Signals are read by calling them like a function:

this.count()

In HTML:

{{ count() }}

For example:

count = signal(10);

console.log(this.count());

Output:

10

Remember:

count    → Signal object
count()  → Current value

Updating with set()

Use set() when you know exactly what the new value should be.

this.count.set(100);

Flow:

count = 10

count.set(100)

     ↓

count = 100

Updating with update()

Use update() when the new value depends on the current value.

this.count.update(value => value + 1);

If:

count = 10

then:

Current value
     ↓
    10
     ↓
value => value + 1
     ↓
    11

set() vs update()

Method Purpose Example
() Read value count()
set() Replace value count.set(10)
update() Calculate from current value count.update(x => x + 1)

Key Points

  • Call a signal to read it: count().
  • Use set() for direct replacement.
  • Use update() when the new value depends on the old value.
  • A signal created with signal() is normally a WritableSignal.

2. What is computed()?

What is computed()?

computed() creates a read-only derived Signal whose value is calculated from other Signals.

For example:

price = signal(100);
quantity = signal(2);

total = computed(() => this.price() * this.quantity());

total depends on:

price
quantity

If either changes, Angular knows that the computed value may need to be recalculated.


Full Simple Program

product.ts

import { Component, computed, signal } from '@angular/core';

@Component({
  selector: 'app-product',
  standalone: true,
  templateUrl: './product.html'
})
export class Product {

  price = signal(100);
  quantity = signal(2);

  total = computed(() =>
    this.price() * this.quantity()
  );

  increaseQuantity() {
    this.quantity.update(value => value + 1);
  }

  changePrice() {
    this.price.set(200);
  }
}

product.html

<h2>Product</h2>

<p>Price: {{ price() }}</p>

<p>Quantity: {{ quantity() }}</p>

<p>Total: {{ total() }}</p>

<button (click)="increaseQuantity()">
  Increase Quantity
</button>

<button (click)="changePrice()">
  Change Price
</button>

Explanation

Initially:

price    = 100
quantity = 2

Our computed signal:

total = computed(() =>
  this.price() * this.quantity()
);

calculates:

100 × 2
   ↓
  200

Therefore:

this.total()

returns:

200

Now suppose:

this.quantity.set(3);

Conceptually:

quantity
2 → 3
   ↓
total depends on quantity
   ↓
100 × 3
   ↓
300

The template now sees:

Total: 300

computed() is Read-Only

This is important.

You can read:

this.total()

But you cannot do:

this.total.set(500);

because total is a computed/read-only signal.

Think:

price ─────┐
           ├──→ computed() ──→ total
quantity ──┘

Writable                Read-only

Another Common Example

firstName = signal('Syed');
lastName = signal('Mohamed');

fullName = computed(() =>
  `${this.firstName()} ${this.lastName()}`
);

Template:

<h2>{{ fullName() }}</h2>

If:

this.firstName.set('Abdul');

then fullName() reflects the new derived value.


Key Points

  • computed() creates derived state.
  • It automatically tracks signals read during its computation.
  • It is read-only.
  • Its calculation is lazy and memoized.
  • Use it when one value can be derived from other state.
  • Don't manually synchronize derived values when computed() can express the relationship.
signal()   → source state
computed() → derived state

3. What is effect()?

What is effect()?

effect() runs side-effecting code whenever the Signals it reads change.

Example:

effect(() => {
  console.log(this.count());
});

Angular tracks the signal read:

this.count()

When count changes, the effect can run again.


Full Simple Program

counter.ts

import {
  Component,
  effect,
  signal
} from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  templateUrl: './counter.html'
})
export class Counter {

  count = signal(0);

  constructor() {

    effect(() => {
      console.log(
        'Count changed:',
        this.count()
      );
    });

  }

  increment() {
    this.count.update(value => value + 1);
  }
}

counter.html

<h2>Count: {{ count() }}</h2>

<button (click)="increment()">
  Increment
</button>

Explanation

The effect is:

effect(() => {
  console.log(
    'Count changed:',
    this.count()
  );
});

Because the effect reads:

this.count()

Angular registers count as a dependency.

Conceptually:

effect()
   │
   └── reads count()
             │
             ↓
      dependency tracked

When:

this.count.update(value => value + 1);

the signal changes.

count
  ↓
changes
  ↓
effect executes
  ↓
console.log(...)

Console might show:

Count changed: 0
Count changed: 1
Count changed: 2
Count changed: 3

When should effect() be used?

Use effect() when a state change needs to cause a side effect.

Examples include:

  • logging
  • synchronizing with browser APIs
  • updating non-reactive third-party libraries
  • custom persistence/integration scenarios

For example:

effect(() => {
  console.log(this.username());
});

Don't use effect() for derived state

Suppose we have:

price = signal(100);
quantity = signal(2);

Don't normally do this:

total = signal(0);

effect(() => {
  this.total.set(
    this.price() * this.quantity()
  );
});

You're manually synchronizing state.

Prefer:

total = computed(() =>
  this.price() * this.quantity()
);

So:

Need calculated value?
        ↓
    computed()

Need side effect?
        ↓
      effect()

This distinction is very important for interviews.


computed() vs effect()

computed() effect()
Creates derived value Performs side effect
Returns a Signal Does not represent derived state
Read with () Runs automatically
Used for calculations Used for external actions
Read-only derived state Side-effect mechanism

Example:

total = computed(() =>
  this.price() * this.quantity()
);

vs:

effect(() => {
  console.log(this.total());
});

Flow:

price ───────┐
             ↓
          computed()
             ↓
           total
             ↓
           effect()
             ↓
        console.log()

4. What is linkedSignal()?

What is linkedSignal()?

linkedSignal() creates a writable signal whose value is linked to other reactive state.

This is useful when:

  • you need a value derived from another Signal,
  • but unlike computed(), you also need to modify that value manually,
  • and you want it to reset/recalculate when its source changes.

This is the main idea:

computed()
    ↓
Derived + Read-only


linkedSignal()
    ↓
Derived/linked + Writable

Simple Real-World Example

Suppose a user chooses a product category.

Each category has a default product.

Category
   ↓
Default selected product

But the user should also be able to manually choose another product.

That's a good use case for linkedSignal().


Full Simple Program

product-selector.ts

import {
  Component,
  linkedSignal,
  signal
} from '@angular/core';

@Component({
  selector: 'app-product-selector',
  standalone: true,
  templateUrl: './product-selector.html'
})
export class ProductSelector {

  category = signal('Laptop');

  selectedProduct = linkedSignal(() => {
    if (this.category() === 'Laptop') {
      return 'Dell';
    }

    return 'iPhone';
  });

  selectLaptopCategory() {
    this.category.set('Laptop');
  }

  selectMobileCategory() {
    this.category.set('Mobile');
  }

  selectHp() {
    this.selectedProduct.set('HP');
  }

  selectSamsung() {
    this.selectedProduct.set('Samsung');
  }
}

product-selector.html

<h2>Product Selector</h2>

<p>Category: {{ category() }}</p>

<p>
  Selected Product:
  {{ selectedProduct() }}
</p>

<hr>

<button (click)="selectLaptopCategory()">
  Laptop Category
</button>

<button (click)="selectMobileCategory()">
  Mobile Category
</button>

<hr>

<button (click)="selectHp()">
  Select HP
</button>

<button (click)="selectSamsung()">
  Select Samsung
</button>

Explanation

We have a normal signal:

category = signal('Laptop');

Then:

selectedProduct = linkedSignal(() => {
  if (this.category() === 'Laptop') {
    return 'Dell';
  }

  return 'iPhone';
});

selectedProduct depends on:

category()

Initially:

category = Laptop
       ↓
linkedSignal()
       ↓
selectedProduct = Dell

So:

this.selectedProduct()

returns:

Dell

But linkedSignal() is Writable

This is the major difference from computed().

The user can manually change:

this.selectedProduct.set('HP');

Now:

category        = Laptop
selectedProduct = HP

That's allowed.

With computed(), this would not be possible.


What happens when the dependency changes?

Suppose:

this.category.set('Mobile');

The linked signal's computation runs based on the new category.

category

Laptop
   ↓
Mobile
   ↓
linkedSignal recalculates
   ↓
selectedProduct
   ↓
iPhone

So the previous manually selected:

HP

is replaced according to the new source state.

This makes linkedSignal() particularly useful for dependent selections and resettable state.


computed() vs linkedSignal()

This is the easiest way to understand linkedSignal().

computed()

category = signal('Laptop');

product = computed(() =>
  this.category() === 'Laptop'
    ? 'Dell'
    : 'iPhone'
);

You can:

this.product();

But cannot:

this.product.set('HP');

because computed() is read-only.


linkedSignal()

category = signal('Laptop');

product = linkedSignal(() =>
  this.category() === 'Laptop'
    ? 'Dell'
    : 'iPhone'
);

You can read:

this.product();

and write:

this.product.set('HP');

But when the reactive source changes, the linked computation can establish a new value.


Comparison

Feature signal() computed() linkedSignal() effect()
Stores value Yes Derived value Yes No
Writable Yes No Yes N/A
Tracks dependencies As source state Yes Yes Yes
Creates derived state No Yes Yes/linked No
Can use set() Yes No Yes No
Can use update() Yes No Yes No
Side effects No No No Yes

Overall Flow

A useful mental model is:

                 Angular Signals
                       │
       ┌───────────────┼────────────────┐
       │               │                │
       ▼               ▼                ▼
    signal()        computed()        effect()
       │               │                │
       ▼               ▼                ▼
 Store state      Derive state      Side effect
       │               │
       │               │
    Writable         Read-only
       │
       │
       └───────────────┐
                       ▼
                 linkedSignal()
                       │
                       ▼
               Linked/derived state
                       +
                    Writable

Key Points

Reading and Updating

count()

reads a Signal.

count.set(10);

directly replaces its value.

count.update(x => x + 1);

calculates a new value from the current value.

computed()

total = computed(
  () => this.price() * this.quantity()
);

Use it for derived state.

It is read-only.

effect()

effect(() => {
  console.log(this.count());
});

Use it for side effects when reactive dependencies change.

Don't use effects as the default mechanism for synchronizing derived state.

linkedSignal()

selected = linkedSignal(
  () => this.defaultValue()
);

Use it when state is linked to reactive dependencies but must remain writable.

The most important distinction is:

signal()       → Writable state

computed()     → Read-only derived state

linkedSignal() → Writable linked/derived state

effect()       → Side effect

Interview Questions and Answers

1. How do you read a Signal?

Call it like a function:

count()

2. How do you update a Signal?

Using set():

count.set(10);

or update():

count.update(x => x + 1);

3. What is the difference between set() and update()?

set() replaces the value directly:

count.set(100);

update() calculates the new value from the current value:

count.update(x => x + 1);

4. What is computed()?

computed() creates a read-only Signal whose value is derived from other reactive dependencies.

total = computed(
  () => this.price() * this.quantity()
);

5. Is a computed Signal writable?

No.

This is invalid:

this.total.set(100);

A computed Signal is read-only.


6. What is effect()?

effect() runs side-effecting code in response to changes in the Signals it reads.

effect(() => {
  console.log(this.count());
});

7. What is the difference between computed() and effect()?

computed() is for creating derived state.

fullName = computed(
  () => `${this.firstName()} ${this.lastName()}`
);

effect() is for performing side effects.

effect(() => {
  console.log(this.fullName());
});

8. What is linkedSignal()?

linkedSignal() creates writable state that is reactively linked to other state.

selectedProduct = linkedSignal(
  () => this.defaultProduct()
);

Unlike computed(), its value can also be manually changed.


9. What is the difference between computed() and linkedSignal()?

The main difference is writability:

computed()
Derived + Read-only

linkedSignal()
Linked/Derived + Writable

For example:

const value = computed(() => source());

You cannot:

value.set(10);

But:

const value = linkedSignal(() => source());

allows:

value.set(10);

10. When should you use linkedSignal() instead of signal()?

Use signal() when the state is independent:

count = signal(0);

Use linkedSignal() when the state has a reactive relationship with another piece of state but still needs to be manually writable.

A common example is:

Country changes
      ↓
Default city changes
      ↓
But user can manually select another city

This is a strong use case for linkedSignal().


Interview Memory Shortcut

signal()
   ↓
"I need state."


computed()
   ↓
"I need a value calculated from other state."


effect()
   ↓
"I need to DO something when state changes."


linkedSignal()
   ↓
"I need state linked to other state,
 but I must also be able to change it."

The most important distinction to remember is computed() vs linkedSignal(): both can derive from reactive state, but computed() is read-only while linkedSignal() is writable and can reset/recompute when its source dependencies change.

← Back to Articles