Global state with #[store]

The #[store] macro turns a function into a global store. The function is called once, on first access, and every next call returns a clone of the value created back then:

    use vertigo::{component, dom, store, Value};

    // Created on the first call, then every call returns the same Value
    #[store]
    fn cart_count() -> Value<u32> {
        Value::new(0)
    }

    #[component]
    fn AddToCart() {
        let add = |_| cart_count().change(|count| *count += 1);

        dom! {
            <button on_click={add}>"Add to cart"</button>
        }
    }

    #[component]
    fn CartBadge() {
        dom! {
            <span>"Cart: " {cart_count()}</span>
        }
    }

    dom! {
        <div>
            <CartBadge />
            <AddToCart />
            <AddToCart />
        </div>
    }

Clones of a Value (as well as of Computed, LazyCache and Rc) share the same state, so all components above see and change the same counter. That's why a store should return something that is shared when cloned. Plain data should be wrapped in a Value or an Rc.

Store with parameters

A store can also take parameters. Then a separate value is kept for every set of arguments, which is handy for caching resources:

    use vertigo::{dom, store, AutoJsJson, LazyCache, RequestBuilder};

    #[derive(AutoJsJson, Clone, PartialEq)]
    pub struct User {
        name: String,
    }

    // A separate cache for every user id
    #[store]
    fn user(id: &u32) -> LazyCache<User> {
        RequestBuilder::get(format!("/api/users/{id}"))
            .ttl_minutes(5)
            .lazy_cache(|status, body| {
                if status == 200 {
                    Some(body.into::<User>())
                } else {
                    None
                }
            })
    }

    // Both render the same cache, so the user is fetched only once
    let header = user(&1).render(|user| dom! { <h3>{&user.name}</h3> });
    let footer = user(&1).render(|user| dom! { <p>"Signed in as " {&user.name}</p> });

    dom! {
        <div>
            {header}
            {footer}
        </div>
    }

Server-side rendering

On the server every request is rendered by a fresh instance of the app, so stores are never shared between users.