Last active
March 24, 2021 01:25
-
-
Save jcampuza/f6b6797a744eeb1b3c5ec6637d6b0d45 to your computer and use it in GitHub Desktop.
Simple observable store class to emulate flux-like state slice with rxjs.
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
import { BehaviorSubject } from 'rxjs'; | |
import { distinctUntilChanged, map } from 'rxjs/operators'; | |
import produce from 'immer'; | |
type StateSetter<T> = Partial<T> | ((s: T) => T | void); | |
/** | |
* Simple abstraction to create an immutable like rxjs store. | |
*/ | |
export abstract class ObservableStore<T = unknown> { | |
/** | |
* Provide the initial State from a factory function | |
*/ | |
abstract getInitialState(): T; | |
private _state = new BehaviorSubject(this.getInitialState()); | |
stateChanged$ = this._state.asObservable(); | |
select<V>(selector: (state: T) => V) { | |
return this.stateChanged$.pipe(map(selector), distinctUntilChanged()); | |
} | |
selectOnce<V>(selector: (state: T) => V) { | |
return selector(this.getState()); | |
} | |
getState() { | |
return this._state.getValue(); | |
} | |
public get state() { | |
return this.getState(); | |
} | |
/** | |
* setState may accept either a function which you can then mutate the current state and it will be updated | |
* with an immutable update, or a partial state update | |
*/ | |
setState(setStateArg: StateSetter<T>) { | |
if (typeof setStateArg === 'function') { | |
const newState = produce(this.getState(), setStateArg) as T; | |
this._state.next(newState); | |
} else { | |
this._state.next({ | |
...this.getState(), | |
...setStateArg, | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment