DEV Community

loading...

20 Lines Simple Store with RxJS

lacolaco profile image Suguru Inatomi ・1 min read
import { distinctUntilChanged, map } from 'rxjs/operators';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

export abstract class Store<T> extends BehaviorSubject<T> {
  constructor(initialState: T) {
    super(initialState);
  }

  public dispatch(fn: (state: T) => T) {
    this.next(fn(this.getValue()));
  }

  public select<R>(fn: (state: T) => R) {
    return this.pipe(map<T, R>(fn), distinctUntilChanged());
  }

  public selectSync<R>(fn: (state: T) => R) {
    return fn(this.getValue());
  }
}

Example: UserStore

import { User } from '../entity/user';
import { Store } from '../../store';

export interface State {
  currentUser: User | null;
}

export class UserStore extends Store<State> {
  constructor() {
    super({
      currentUser: null,
    });
  }

  get currentUser$() {
    return this.select(state => state.currentUser);
  }
  get currentUser() {
    return this.selectSync(state => state.currentUser);
  }

  setCurrentUser(user: User) {
    this.dispatch(state => ({
      ...state,
      currentUser: user,
    }));
  }
}

Discussion

pic
Editor guide