The AppBasicStateService
provides an easy way to maintain a state for a specific part of the application, allowing components to read from and update that state. The examples below will cover:
- Initializing the state in a component.
- Updating the state in a component.
- Subscribing to state changes in a component.
- Unsubscribing and cleanup.
In the component's constructor or lifecycle method, you can initialize a state
by calling initState()
on the AppBasicStateService
and providing an identifier
and initial state.
constructor(private basicStateService: AppBasicStateService) {
this.basicStateService.initState(
RegisteredStates.SFTP_IMPORT_LIST_FILTERS,
initialFilters
);
}
To update the state, you'd use the setState()
method, passing the state
identifier and the new state.
onChangeFilters(newFilters: ISftpImportListFilters): void {
this.basicStateService.setState(
RegisteredStates.SFTP_IMPORT_LIST_FILTERS,
newFilters
);
}
To react to changes in the state, you can subscribe to the state in the component's
lifecycle methods (e.g., ngOnInit
, ngAfterViewInit
).
filterSubscription: Subscription;
ngAfterViewInit(): void {
this.filterSubscription = this.basicStateService
.getState(RegisteredStates.SFTP_IMPORT_LIST_FILTERS)
.subscribe((newFilter) => {
// Handle the new filter value
this.currentFilter = newFilter;
});
}
ngOnDestroy(): void {
this.filterSubscription.unsubscribe();
this.basicStateService.unregisterState(
RegisteredStates.SFTP_IMPORT_LIST_FILTERS
);
}
This is an alternative approach to the one above, which uses the takeUntil RxJS operator.
Why is this setup different?
We are using the takeUntil RxJS operator, which ensures that the subscription is automatically unsubscribed when this.destroy$ emits a value. This is a common pattern in Angular to handle unsubscriptions and avoid memory leaks. The this.destroy$ is a Subject, and when the component's ngOnDestroy lifecycle method is called, we emit a value with this.destroy$.next(), effectively cleaning up any subscriptions. This is mentioned further in the "Unsubscribing and Cleanup" section below.
public ngAfterViewInit(): void {
this.basicStateService
.getState(RegisteredStates.SFTP_IMPORT_LIST_FILTERS)
.pipe(takeUntil(this.destroy$))
.subscribe(async (newFilter) => {
if (newFilter) {
await this.updateFilters(newFilter);
}
});
}
public ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
this.basicStateService.unregisterState(
RegisteredStates.SFTP_IMPORT_LIST_FILTERS
);
}
It's good practice to unsubscribe from Observables to prevent memory leaks.
In the ngOnDestroy
lifecycle hook, ensure you unsubscribe. Both the takeUntil
and Subscription
approaches are below. You can use either approach, but
the takeUntil
approach can be more flexible if you need to unsubscribe from
multiple Observables.
private filterSubscription: Subscription;
ngOnDestroy(): void {
this.filterSubscription.unsubscribe();
this.basicStateService.unregisterState(
RegisteredStates.SFTP_IMPORT_LIST_FILTERS
);
}
private destroy$: Subject<void> = new Subject<void>();
public ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
this.basicStateService.unregisterState(
RegisteredStates.SFTP_IMPORT_LIST_FILTERS
);
}
- Initialization: It's usually best to initialize the state early in the component's lifecycle (e.g., in the constructor or
ngOnInit
). - Error Handling: The service has built-in error handling, which will log errors if you attempt to update a state that hasn't been initialized. Make sure to look for these errors while developing and add any needed try/catch blocks.
- Cleanup: Always unsubscribe from any Observables and deregister any states in the
ngOnDestroy
method to prevent memory leaks.- The component responsible for initializing the state should be the one to deregister the state in the
ngOnDestroy
method.
- The component responsible for initializing the state should be the one to deregister the state in the
- State Identifiers: Use the
RegisteredStates
enum to register state identifiers. This will help prevent typos and make it easier to find where a state is registered.
I hope this helps! Adjust as needed for your specific use case.