Skip to content

AidanHibbard/olallie

Repository files navigation

Olallie

GitHub Actions Workflow Status NPM License NPM Downloads NPM Version NPM Unpacked Size

Background

Built to be a lightweight state management tool for framework-less projects.

The name Olallie comes from a lake in Oregon.

Quick links

Installation

  • Install the module

    npm i olallie
  • Import createStore

    import createStore from 'olallie';
    // or
    const createStore = require('olallie');

Example usage

import createStore from 'olallie';
// or
// const createStore = require('olallie');

const store = createStore({
  state: {
    count: 0
  },
  actions: {
    add(value: number) {
      // Actions have access to
      // state, getters, and other actions
      this.count += value;
      return this.count;
    },
  },
  getters: {
    // State is automatically inferred
    doubled: (state) => state.count * 2,
  },
});

// Call options from the store
store.add(1); // 1
const count = store.count; // 1
const doubled = store.doubled; // 2

Documentation

State

State is always required when creating a new store, and should be an object.

const stateStore = createStore({
  state: {
    count: 1,
  },
});

State values can be accessed from the store itself with type-safety.

// (property) count: number
const count = stateStore.count;

You can also apply custom types to your state.

interface State {
  count: number;
}

const stateStore = createStore({
  state: {
    count: 1,
  } as State,
});

Actions

Actions should update, and, or return state values. They have access to state, getters, and other actions through this.

const store = createStore({
  state: {
    count: 0
  },
  actions: {
    add(value: number) {
      this.count += value;
      return this.count;
    },
    double() {
      this.count = this.doubled;
      return this.count;
    },
    addAndDouble(value: number) {
      this.add(value);
      return this.double();
    },
  },
  getters: {
    doubled: (state) => state.count * 2,
  },
});

Store actions can also be async.

const store = createStore({
  state: {
    response: undefined,
  },
  actions: {
    async fetch(userId: string): Promise<boolean> {
      let data;
      await new Promise((resolve) => {
        setTimeout(() => {
          data = {
            id: userId,
            name: 'John Doe'
          };
          resolve(true);
        }, 1);
      });
      this.response = data;
    },
  },
});

await store.fetch('abcd');
const user = store.response;

Getters

Getters should return computed values without manipulating the state itself.

const store = createStore({
  state: {
    firstName: 'John',
    lastName: 'Doe'
  },
  getters: {
    // State is automatically typed
    /*
    (parameter) state: {
      firstName: string;
      lastName: string;
    }
    */
    fullName: (state) => `${state.firstName} ${state.lastName}`;
  }
});

const name = store.fullName; // "John Doe"

Listeners

Listeners provide a helpful bit of reactivity with your store. They use the Event Target API under the hood, and will dispatch a Custom Event when a state value is changed.

The listen() method will provide a list of your stores state keys to choose from, and automatically infer the value for you.

const store = createStore({
  state: {
    count: 0,
  },
});

// (parameter) event: StoreEvent<S, K>
const listener = store.listen('count', ({ detail, timeStamp }) => {
  // Values are type-safe
  /*
  param (detail): {
    value: number;
    oldValue: number;
  }
  */
  console.log('%j', {
    newValue: detail.value,
    oldValue: detail.oldValue,
    timeStamp
  });
}, false);

store.count++;

Listeners can be removed by calling unlisten().

listener.unlisten();

Contributing

Follow the contributor guidelines when opening a PR, or issue.

Project setup

  1. Install the version of node listed in the .nvmrc

  2. Install modules

  3. Run spec to lint & unit test