Skip to content

Instantly share code, notes, and snippets.

@jtomaszewski
Created January 11, 2019 11:05
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtomaszewski/7488fc5882f9ce999a29056ca59ece8c to your computer and use it in GitHub Desktop.
Save jtomaszewski/7488fc5882f9ce999a29056ca59ece8c to your computer and use it in GitHub Desktop.
Example implementation of StatefulComponent in Angular
// Code authored by [Recruitee](https://recruitee.com)
// License: MIT
import { Injectable, ChangeDetectorRef } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
const immutableStateInvariantMiddleware = process.env.NODE_ENV !== 'production'
? require('redux-immutable-state-invariant').default
: null;
export interface RtStatefulComponent<State> {
rtStateWillInit?(initialState: State): void;
rtStateWillChange?(prevState: State, nextState: State): void;
}
// Extend this class when you want your component to have an internal state.
// (a state which will be controlled by the component itself
// and on which the component's template/children is dependent).
//
// Usage example:
// ```
// type State = {
// expanded: boolean
// };
//
// export class MyComponent extends RtStatefulComponent<State> {
// constructor(protected cdRef: ChangeDetectorRef) {
// super(cdRef);
// this.createState({
// expanded: false
// });
// }
//
// // usage example: accessing and changing state
// public handleExpandedChange(nextExpanded: boolean = !this.state.expanded): void {
// this.setState({ expanded: nextExpanded });
// }
// }
// ```
@Injectable()
export abstract class RtStatefulComponent<State> {
protected state$: Observable<State>;
private __state$: BehaviorSubject<State>;
private __immutableStateInvariantMiddleware: any;
constructor(protected cdRef: ChangeDetectorRef) {}
public get state(): State {
return this.__state$.getValue();
}
protected createState(
initialState: State,
): void {
if (this.rtStateWillInit) {
this.rtStateWillInit(initialState);
}
this.__state$ = new BehaviorSubject<State>(initialState);
this.state$ = this.__state$.asObservable();
}
protected setState(nextState: State): void {
const next = () => {
const previousState = this.state;
if (this.rtStateWillChange) {
this.rtStateWillChange(previousState, nextState);
}
this.__state$.next(nextState);
this.cdRef.detectChanges();
};
if (process.env.NODE_ENV !== 'production') {
this.__immutableStateInvariantMiddleware = immutableStateInvariantMiddleware({})({
getState: () => this.state,
});
this.__immutableStateInvariantMiddleware(next)({ type: 'setState', nextState });
} else {
next();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment