Global State
Under the hood, @joystick.js/ui
includes a global state library called Cache. Similar to popular libraries like Redux, Cache allows you to create a "store" or "cache" for storing global data. It features a simple API for getting, setting, and unsetting data from a cache as well as listening for changes to a cache.
By default, Joystick initializes a cache for you and makes it accessible as a named export at global_state
(and an alias on the default joystick
export at joystick.global_state
).
/ui/pages/store/index.js
import joystick, { global_state } from "@joystick.js/ui-canary";
import Cart from '../../components/cart/index.js';
const Store = joystick.component({
events: {
'click [data-item-id]': (event = {}, instance = {}) => {
global_state.set((state = {}) => {
return {
...state,
cart: [
...state.cart || [],
{ id: event.target.getAttribute('data-item-id'), }
],
};
});
},
},
render: ({ data, component, i18n }) => {
return `
<div>
<div class="store">
<button data-item-id="book">Add a Book to Cart</button>
<button data-item-id="t-shirt">Add a T-Shirt to Cart</button>
<button data-item-id="apple">Add an Apple to Cart</button>
</div>
${component(Cart)}
</div>
`;
},
});
export default Store;
Above, we've imported the named export global_store
from @joystick.js/ui
. Down in our render()
function, we've set up a mock "store" with three items as <button></button>
tags. Up in our events
, we listen for a click
event on each button. When there's a click, we call to global_state.set()
passing a function that will be responsible for "compiling" the updated version of our global state.
From it, we return
an object representing the new global state. First, we copy the current value of state
(if one is present) and then we set the value of cart
to an array containing two things:
- If present, the existing value of
state.cart
on global state. - An object representing the item we're adding to the cart (specified by its
data-item-id
attribute`.
This will get items added to our global state. Next, let's wire up the Cart
component we're rendering above.
/ui/components/cart/index.js
import joystick, { global_state } from '@joystick.js/ui-canary';
const Cart = joystick.component({
state: {
cart: [],
},
lifecycle: {
on_mount: (instance = {}) => {
global_state.on('change', (state = {}, event = '', user_event_label = '') => {
instance.set_state({ cart: state?.cart });
});
}
},
events: {
'click button': (event = {}, instance = {}) => {
global_state.set((state = {}) => {
return {
...state,
cart: [
...state.cart || [],
{ id: event.target.getAttribute('data-item-id'), }
],
};
});
},
},
render: ({ state, each, when }) => {
return `
<div>
<div class="items">
${when(state?.cart?.length === 0, `
<p>No items in cart</p>
`)}
${when(state?.cart?.length > 0, `
<ul>
${each(state?.cart, (item) => {
return `<li>${item.id} <button>X</button></li>`;
})}
</ul>
`)}
</div>
</div>
`;
},
});
export default Cart;
Again, importing global_state
from @joystick.js/ui
, in this component, we add a change
event listener to our global_state
via the .on()
method.
The .on()
method takes two arguments: an event
to listen for and a callback
to call when that event occurs. Here, we just want to be notified of a change
to the global state and copy the state.cart
value over to the local or component state so that we can render our cart's items.
API Reference
Object API
global_state: {
get: (path: string) => object,
on: (
event_type: 'string',
callback: (existing_state: object, event: string, type_of_change: string) => void
) => void,
set: (
callback: (existing_state: object) => object,
user_event_label: string
) => void,
unset: (path: string, user_event_label: string) => event,
}
Parameters
-
get function
A
function
for retrieving the current global state value. Can optionally receive apath
to retrieve from the global state value (e.g.,cart
). If a value is nested, dot notation can be used (e.g.,my.nested.value
) to access it directly. -
on function
A
function
for handling global store events. Takes anevent_type
(set
,unset
, orchange
) and acallback
function to call when the event is received.-
event_type string Required
A
string
describing the event type to listen for (one of:set
,unset
, orchange
). -
callback function Required
A
function
called when the specifiedevent_type
occurs. Receives:-
existing_state object
An
object
representing the current global state value. -
event string
A
string
describing the event that occured (one of:set
,unset
, orchange
). -
user_event_label string
If passed, a
string
containing the user-specified event label (e.g.,ADD_TO_CART
orEMPTY_CART
).
-
-
-
set function
A
function
for setting the global state value. Receives a callback function that's expected to return anobject
representing the updated state.-
callback function Required
A
function
receiving the current global state value. Should return anobject
representing the updated state. -
user_event_label string
A
string
specifying the relevancy of the set event (e.g.,ADD_TO_CART
).
-
-
unset function
A
function
for unsetting the global state value. Can receive an optionalpath
as astring
to remove from the global state value. If nopath
is provided, the entire global state value is unset.-
path string
A
string
specifying a path to remove on the global state. Can use dot notation to unset a nested value (e.g.,nested.value.to.unset
). -
user_event_label string
A
string
specifying the relevancy of the unset event (e.g.,EMPTY_CART
).
-