Created
January 11, 2019 11:05
-
-
Save jtomaszewski/7488fc5882f9ce999a29056ca59ece8c to your computer and use it in GitHub Desktop.
Example implementation of StatefulComponent in Angular
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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