@podium/store
This is a client-side library that provides a reactive data store using nanostores on top of @podium/browser's MessageBus
. It includes some ready-made stores and helpers for you to make reactive stores for your own events.
By using reactive state backed by MessageBus
you can seamlessly share state between different parts of a Podium application. If a podlet changes the value of shared state, all other podlets using that value can update.
Usage
To install:
npm install @podium/store
Use an included store in your client-side application:
// store/user.js
import { $authentication } from "@podium/store";
import { computed } from "nanostores";
// You can optionally make a computed value based on the included store
export const $loggedIn = computed($authentication, (authentication) =>
Boolean(authentication.token)
);
// Colocating actions with the store makes it easier to
// see what can trigger updates.
export function logIn(token) {
$authentication.set({ token });
}
export function logOut() {
$authentication.set({ token: null });
}
Use the reactive store to do minimal updates of your UI when state changes. Nanostores supports multiple view frameworks:
This example shows a React component:
// components/user.jsx
import { useStore } from "@nanostores/react";
import { $loggedIn } from "../stores/user.js";
export const User = () => {
const loggedIn = useStore($loggedIn);
return <p>{loggedIn ? "Welcome!" : "Please log in"}</p>;
};
This is the same component in Lit:
// components/user.js
import { StoreController } from "@nanostores/lit";
import { $loggedIn } from "../stores/user.js";
class User extends LitElement {
loggedInController = new StoreController(this, $loggedIn);
render() {
return html`<p>
${this.loggedInController.value ? "Welcome!" : "Please log in"}
</p>`;
}
}
customElements.define("a-user", User);
Create your own reactive state
By using the included helper you can make your reactive state sync between the different parts of a Podium application.
API
$authentication
Type: map
import { $authentication } from "@podium/store";
atom(channel, topic, initialValue)
Create your own atom
that syncs between parts of a Podium application using the MessageBus.
This method requires the following arguments:
option | type | details |
---|---|---|
channel | string | Name of the channel |
topic | string | Name of the topic |
payload | object | The initial value. Replaced if peek(channel, topic) returns a value. |
import { atom } from "@podium/store";
const $reminders = atom("reminders", "list", []);
map(channel, topic, initialValue)
Create your own map
that syncs between parts of a Podium application using the MessageBus.
This method requires the following arguments:
option | type | details |
---|---|---|
channel | string | Name of the channel |
topic | string | Name of the topic |
payload | object | The initial value. Replaced if peek(channel, topic) returns a value. |
import { map } from "@podium/store";
const $user = map("user", "profile", { displayName: "foobar" });
deepMap(channel, topic, initialValue)
Create your own deepMap
that syncs between parts of a Podium application using the MessageBus.
This method requires the following arguments:
option | type | details |
---|---|---|
channel | string | Name of the channel |
topic | string | Name of the topic |
payload | object | The initial value. Replaced if peek(channel, topic) returns a value. |
import { deepMap, listenKeys } from "@podium/store";
export const $profile = deepMap({
hobbies: [
{
name: "woodworking",
friends: [{ id: 123, name: "Ron Swanson" }],
},
],
skills: [["Carpentry", "Sanding"], ["Varnishing"]],
});
listenKeys($profile, ["hobbies[0].friends[0].name", "skills[0][0]"]);