Concorde decorator — @subscribe. Keeps a Lit property in sync with a read-only slice of the DataProvider store. You pass a DataProviderKey; when that path changes, the property updates and the component re-renders. Doc ID: docs/_decorators/subscribe. Keywords: Concorde, supersoniks, docs/_decorators/subscribe, subscribe, @subscribe, decorator, DataProviderKey, | Shape of the object at that path (, , , , …) |
| **Key** | , — static path (, ) or dynamic (, (e.g. , ) — often filled via [. URL: https://concorde.supersoniks.org/crawl/docs/_decorators/subscribe.html.
@subscribe
Keeps a Lit property in sync with a read-only slice of the DataProvider store. You pass a DataProviderKey; when that path changes, the property updates and the component re-renders.
Typical setup (same idea as My first component):
| Piece | Role |
|---|---|
Type T |
Shape of the object at that path (DocsUserData, { count: number }, …) |
| Key | DataProviderKey<T, U> — static path ("cart") or dynamic ("users.${userIndex}", "${dataProvider}") |
| Scope on the host | Properties listed in U (e.g. dataProvider, userIndex) — often filled via @ancestorAttribute |
@subscribe(key) |
Mirrors the store into @state() (or another property); read-only from the component side |
For writing back to the store from component state, use @publish. In templates, the same paths work with sub().
Import
import { subscribe } from "@supersoniks/concorde/decorators";
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
type Data = { count: number };
const dataKey = new DataProviderKey<Data>("data");
@subscribe(dataKey.count)
@state()
count = 0;
Static path
The key path is fixed. The property type must match T at that segment.
const cartKey = new DataProviderKey<{ items: string[] }>("cart");
@subscribe(cartKey)
@state()
cart: { items: string[] } | null = null;
Dynamic path and scope
Placeholders ${prop} in the key string are resolved from properties on the same component. While a value is null/undefined, the subscription is inactive; optional { skipEmptyPlaceholder: true } also waits on "". Full rules: Dynamic path placeholders.
Declare dynamic props in the key’s second generic so TypeScript expects them on the host:
type User = { firstName: string; lastName: string; email: string };
@subscribe(new DataProviderKey<User, { userIndex: number }>("demoUsers.${userIndex}"))
@state()
user: User | null = null;
@property({ type: Number }) userIndex = 0;
When userIndex changes, @subscribe re-resolves the path and refreshes user.
Row / ancestor scope
List items (and wrappers like <div dataProvider="…">) set which branch the child reads. Pattern from the tutorial:
export const rowKey = new DataProviderKey<
User,
{ dataProvider: string | null }
>("${dataProvider}");
@ancestorAttribute("dataProvider")
dataProvider: string | null = null;
@subscribe(rowKey)
@state()
user: User | null = null;
Demo
<docs-demo-sources for="demo-subscribe-dynamic"></docs-demo-sources>
<demo-subscribe-dynamic></demo-subscribe-dynamic>
See also
- Data flow — overview
- DataProviderKey — paths and host generics
- Dynamic path placeholders —
${prop}resolution andskipEmptyPlaceholder - sub() — same paths inside
htmltemplates