LinkedSignal in Angular 19: Say Goodbye to Effect-Based State Sync
Amos Isaila

Amos Isaila @amosisaila

About: Angular enthusiast. https://www.youtube.com/channel/UCATsbPmCzU5dVL_sbNwbb5w

Location:
Spain
Joined:
May 8, 2017

LinkedSignal in Angular 19: Say Goodbye to Effect-Based State Sync

Publish Date: Jul 6
0 0

Angular 19 introduces a powerful new reactive primitive: linkedSignal. This feature represents a significant shift in how we handle dependent state management, reducing our reliance on Effects.

What is LinkedSignal?

A linkedSignal represents state that is reset based on a provided computation. Conceptually, it maintains state that is only valid within the context of another source signal. This makes it perfect for scenarios where one piece of state depends on another.

Key Features

1. Two Forms of Usage

Shorthand Form

const counter = signal(0);
const doubledCounter = linkedSignal(() => counter() * 2);
Enter fullscreen mode Exit fullscreen mode

Full Form with Source Tracking

const items = signal(['A', 'B', 'C']);
const selectedItem = linkedSignal({
  source: items,
  computation: (currentItems, previous) => {
    // Access to both current and previous state
    return previous && currentItems.includes(previous.value)
      ? previous.value
      : currentItems[0];
  }
});
Enter fullscreen mode Exit fullscreen mode

2. Writable Signal Capabilities

LinkedSignals implement the WritableSignal interface, meaning they support:

  • Reading values with ()
  • Setting values with .set()
  • Updating values with .update()
  • Converting to readonly with .asReadonly()

3. Previous Value Access

One of the most powerful features is access to the previous state in computations:

linkedSignal({
  source: parentState,
  computation: (current, previous) => {
    if (!previous) return defaultValue;
    return determineNewValue(current, previous.value);
  }
});
Enter fullscreen mode Exit fullscreen mode

Common Use Cases

Currently, when developers need to synchronize two pieces of state, they often reach for effects. Consider a common scenario: you have a list of items and a selected item. When the list changes, you want to reset or update the selection. Many developers implement this using effects, which isn’t ideal for state management.

Let me show you a practical implementation using a cats facts application, where we’ll demonstrate the power of linkedSignal.

1. Selection State Management

// Before (using Effect)
@Component({...})
class CatFactsComponent {
  factsResource = this._catFactsService.getCatsFacts;
  selectedItem = signal<string | null>(null);

  constructor() {
    effect(() => {
      this.factsResource.value(); // Watch for changes
      this.selectedItem.set(null); // Reset selection
    });
  }
}

// After (using LinkedSignal)
@Component({...})
class CatFactsComponent {
  factsResource = this._catFactsService.getCatsFacts;
  selectedItem = linkedSignal<string[] | undefined, number | null>({
    source: this.factsResource.value,
    computation: (items) => null
  });
}
Enter fullscreen mode Exit fullscreen mode

2. Smart Selection with Previous State

In the previous example if I reload my request, the selection will become null and not item will be selected. But playing with the previous value we can still have the previous selected index when we refreshing data:

selectedItem = linkedSignal<string[] | undefined, number>({
  source: this.factsResource.value,
  computation: (facts, previous) => {
    if (previous && facts && previous.value < facts.length) {
      return previous.value; // Preserve valid selections
    }
    return -1; // Reset when needed
  }
});
Enter fullscreen mode Exit fullscreen mode

3. Pagination

You current page selection will be a linkedSignal. It will become the first one when we have no data and we will keep the current page when refreshing a we have more data than our items per page.

currentPage = linkedSignal<string[] | undefined, number>({
  source: this.factsResource.value,
  computation: (facts, previous) => {
    if (!facts) return 0;
    if (previous && previous.value * this.itemsPerPage() < facts.length) {
      return previous.value; // Keep current page if still valid
    }
    return 0; // Reset to first page if data changes significantly
  }
});
Enter fullscreen mode Exit fullscreen mode

You can find the full implementation in the source code appended at the end of this post.

Advantages Over Previous Approaches

  • No race conditions like we might see with effects
  • Clearer intention in the code
  • Better TypeScript support
  • More predictable behavior

Computed vs LinkedSignal

  • Writability
    -
    computed: Read-only, can't modify directly
  • linkedSignal: Writable, can .set() and .update()
  • State Management
    -
    computed: Pure derivation, always reflects source - linkedSignal: Maintains its own state, recomputes on source changes
  • Previous Value Access
    -
    computed: No access to previous value - linkedSignal: Access to previous source and value

Use Cases

// ✨ Computed: For derived data
const totalPrice = computed(() => 
  items().reduce((sum, item) => sum + item.price, 0)
);

// ✨ LinkedSignal: For dependent state
const selectedItem = linkedSignal({
  source: items,
  computation: (items, prev) => 
    prev?.value && items.includes(prev.value) 
      ? prev.value 
      : null
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

While linkedSignal looks promising for handling dependent state, it’s important to note:

⚠️ WARNING: This is still experimental!

🙏 Call to Action : The Angular team needs our help! Try it out and provide feedback:

  • Test it in different scenarios
  • Share edge cases you find
  • Suggest improvements
  • Report bugs
  • Propose new use cases

Remember: Your feedback shapes the future of Angular! Let’s help make linkedSignal even better before it’s finalized.

🔗 Ready to experiment? Check the PR.

🔗 Link to the repository of the examples provided in this post.

📢 Share your thoughts.

Thanks for reading so far 🙏

I’d like to have your feedback so please leave a comment , clap or follow. 👏

Spread the Angular love! 💜

If you really liked it, share it among your community, tech bros and whoever you want! 🚀👥

Don’t forget to follow me and stay updated: 📱

Thanks for being part of this Angular journey! 👋😁

Originally published at https://www.codigotipado.com.

Comments 0 total

    Add comment