Skip to content

Pier

A pier is a scope. It runs some setup code, and everything created during that run belongs to it.

When the component that opened the pier unmounts, the scope is cleared and all of it goes away.

Wrap the part of your UI that needs the state.

<PierProvider pier="Top">
<Counter />
</PierProvider>

Svelte has no provider component. providePier uses setContext directly, so you call it in the script block of the component that owns the scope.

Your pier key is an enum. One variant per scope your app needs.

#[derive(Serialize, Deserialize)]
pub enum Pier {
Top,
Panel,
}
wasm_bindgen_enrol_sphere!(@pier, Pier, run_pier, Converter);
fn run_pier(key: Pier) {
match key {
Pier::Top => {
set_js_hail_dispatcher();
provide_context(Stock::new(State { count: 0 }));
}
Pier::Panel => {
provide_context(Stock::new(String::from("hello")));
}
}
}

run_pier runs once, when the provider mounts. It returns nothing. Its job is to create state and put it in context.

provide_context stores a value on the pier. use_context finds it.

// in run_pier
provide_context(Stock::new(State { count: 0 }));
// anywhere inside that pier
let state = use_context::<Stock<State>>().unwrap();

Lookup walks up the parent chain, the same way React context does. A hail running inside Panel can see anything Top provided.

Context is keyed by type. Providing two values of the same type means the nearer one wins.

That is why the examples wrap bare types in a newtype:

#[derive(Clone, Copy)]
struct PanelInfo(Stock<String>);

Two different Stock<String> values would otherwise collide.

Piers form a tree. Nest a provider inside another and the inner pier becomes a child of the outer one.

<PierProvider pier="Top">
<Counter />
<PierProvider pier="Panel">
<Panel />
</PierProvider>
</PierProvider>

Use a child pier when a section of the UI needs its own state that should disappear with it: a modal, a tab panel, a row being edited.

A child pier is not isolated, though. Its own run_pier, and every hail and tell that runs inside it, can use_context anything an ancestor provided. So a child pier adds state without having to re-provide what the parent already set up, which is what makes small, short-lived scopes cheap.

When the provider unmounts, its scope is cleared.

Clearing cascades to children, so dropping a parent frees the whole subtree. It is also idempotent and order-independent, which means each framework adapter can simply clear its own pier on unmount and stay correct no matter what order components tear down in.

You do not write cleanup code. Every stock, memo, effect, and action created inside the pier goes away with it.

A pier holds the state. Hails are how JS reads it.