Skip to content

Instantly share code, notes, and snippets.

@shannonmoeller
Last active May 8, 2020 23:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shannonmoeller/b0e8a26bd742b382760aff0b2c0ac4d5 to your computer and use it in GitHub Desktop.
Save shannonmoeller/b0e8a26bd742b382760aff0b2c0ac4d5 to your computer and use it in GitHub Desktop.
JavaScript stores for devs who like stores.

Arbitrary Values

export function createStore(state) {
  const listeners = new Set();

  return {
    get() {
      return state;
    },

    set(next) {
      state = typeof next === 'function'
        ? next(state)
        : next;

      return new Promise((resolve) => {
        listeners.forEach((fn) => fn(state));
        resolve();
      });
    },

    subscribe(fn, { immediate } = {}) {
      listeners.add(fn);

      if (immediate) {
        fn(state);
      }

      return () => {
        listeners.delete(fn);
      };
    },
  };
}

Objects

export function createStore(state) {
  const listeners = new Set();

  return {
    get() {
      return state;
    },

    set(patch) {
      const prev = state;
      const next = { ...prev, ...patch };

      state = next;

      listeners.forEach((fn) => {
        fn(next, prev);
      });
    },

    subscribe(fn, immediate = true) {
      listeners.add(fn);

      if (immediate) {
        fn(state);
      }

      return () => {
        listeners.delete(fn);
      };
    },
  };
}

Classes

class Store {
  constructor(initialState) {
    this.listeners = new Set();
    this.state = initialState;
  }

  set(patch) {
    const prev = this.state;
    const next = { ...prev, ...patch };

    this.state = next;

    this.listeners.forEach((fn) => {
      fn(next, prev);
    });

    return this;
  }

  subscribe(fn, immediate = true) {
    this.listeners.add(fn);

    if (immediate) {
      fn(this.state);
    }

    return () => {
      this.listeners.delete(fn);
    };
  }
}
class AppStore extends Store {
  constructor() {
    super({
      foo: 'hello',
      bar: 'world',
    });
  }

  setFoo(foo) {
    this.set({ foo });
  }

  setBar(bar) {
    this.set({ bar });
  }
}
const appStore = new AppStore();

appStore.addListener(console.log);

appStore.setFoo('goodnight');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment