Skip to content

Instantly share code, notes, and snippets.

@jcampuza
Last active March 24, 2021 01:25
Show Gist options
  • Save jcampuza/f6b6797a744eeb1b3c5ec6637d6b0d45 to your computer and use it in GitHub Desktop.
Save jcampuza/f6b6797a744eeb1b3c5ec6637d6b0d45 to your computer and use it in GitHub Desktop.
Simple observable store class to emulate flux-like state slice with rxjs.
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