Home/Docs/Global Store
Store

Global Store

Component state lives and dies with its component. For state shared across components — a cart, the signed-in user, app settings — Olum ships a zustand-style global store: define it once in a plain .js module, import it anywhere, and every component that reads it re-renders automatically when it changes.

store.js
import { store } from "olum";

export const cart = store({
  items: [],
  add(name) {
    this.items.push(name);
  },
  clear() {
    this.items = [];
  },
});

State and the actions that mutate it live in the same object — methods reach the state through this. Then any component, in any file, imports it like a normal module. One component writes:

Shelf.html
<script>
  import { cart } from "./store";

  const products = ["Compass", "Canteen", "Rope"];
</script>

<for each="product of products">
  <button onclick="cart.add(product)">Add {product}</button>
</for>

…and a different component reads — always in sync, with no props and no event forwarding:

Basket.html
<script>
  import { cart } from "./store";
</script>

<p>
  <strong>{cart.items.length}</strong>
  {cart.items.length === 1 ? "item" : "items"} in the basket
</p>

<if when="cart.items.length">
  <ul>
    <for each="name of cart.items">
      <li>{name}</li>
    </for>
  </ul>
  <button onclick="cart.clear()">Empty basket</button>
</if>

No providers, no wiring: a component subscribes by reading the store during render. When the store changes, every subscribed component still in the DOM re-renders; components that only write (and never read) are untouched.

💡

A store module is just a .js file — only page.html files become routes, so keep it wherever it reads best: next to the pages that share it, or in utils/ for app-wide stores.

Actions

Use method shorthand (add() {}), not arrow functions — arrows don't bind this, so they can't reach the store's state:

export const cart = store({
  items: [],
  add(item) { this.items.push(item); },     // ✓ method — `this` is the store
  clear: () => (this.items = []),           // ✗ arrow — `this` is NOT the store
});

Mutating from outside an action works too — cart.items = [] in a component handler is fine. Actions are a convention for keeping the logic next to the data, not a requirement.

store(init) takes a plain object — the same rule as component state. Class instances aren't accepted as the store root.

One store per concern beats one giant store: each is just an export, so split freely (cart.js, session.js, settings.js) and let components import only what they read.

store ships in the separate olum-store package, which olum auto-loads — nothing to set up. If the package is removed from the project, calling store() throws "store is unavailable"; the rest of the framework keeps working.