In this post, we’ll explore how to combine Angular’s Signals with Dependency Injection to create predictable, reactive, and reusable component state.
A Signal is a reactive value that notifies dependents when it changes.
Example:
import { signal } from '@angular/core';
const count = signal(0);
count(); // 0
count.set(1);
Managing State via Dependency Injection
Create a StateService that holds signals.
Provide it at the component or root level.
@Injectable({ providedIn: 'root' })
export class CounterState {
count = signal(0);
increment() {
this.count.update(c => c + 1);
}
}
Scoped State with Component Providers
@Component({
selector: 'app-parrent',
providers: [CounterState],
templateUrl: './parent.html'
})
export class ParentComponent {
state = inject(CounterState);
}
Using the State in child Components
@Component({
selector: 'app-child',
template: `
<button (click)="state.increment()">+</button>
<p>Count: {{ state.count() }}</p>
`
})
export class ChildComponent {
state = inject(CounterState);
}
Best Practices
- Keep services pure and focused on state logic.
- Avoid too much global state.
- Use computed for derived state.
- Prefer DI scoping over manual signal creation in many components.
A complete example is here
Conclusion
The main benefits:
- Reactive updates with zero boilerplate
- Clean state isolation using DI
- Easier debugging and reasoning
Next steps:
- Try integrating Signals in existing projects
- Explore computed() and effect() for advanced patterns
Happy coding!
I hope you found it helpful. Thanks for reading!
Let's get connected! You can find me on:
Top comments (0)