π§ MemoryΒΆ
When you fetch data from an API, you often get back far more than the current page needs to display. A product catalogue with 2,000 items. A message history with 500 entries. A full user dataset.
If you pass all of that into Cleraβs data system, the binding engine has to scan every key on every update cycle. For small UI state that overhead is nothing. For large datasets it adds up and the app slows down.
app.memory solves this. It is a plain JavaScript object that lives completely outside the binding engine. Clera never watches it, never scans it, and never patches the DOM because of it. You use it as an immediate data cache: load your full dataset once, keep it in memory, then pull only what the current view needs into the binding system.
// 2,000 items loaded once: Clera never touches this
app.memory.products = apiResponse.products;
// Only 40 items enter the binding system
context.data({
visibleProducts: app.memory.products.slice(0, 40)
});
The binding engine only ever sees 40 items no matter how large the full dataset grows. Memory access is instant because it is just a plain object lookup.
This is Cleraβs memory management model. app.memory is the holding layer. context.data() and app.data() are the display layer. Data flows one way:
app.memory β context.data / app.data β UI
π― The ruleΒΆ
Store large or non-UI data in
app.memory. Expose only what the current view needs viacontext.data()orapp.data().
π§ The modelΒΆ
app.memory β holding layer: large datasets, cache, session state
app.data β global display layer: small, reactive, drives the DOM
context.data β page display layer: scoped to one page, reactive
Memory holds data. Data drives the UI.
βοΈ Basic usageΒΆ
app.memory is a plain object. No methods, no wrappers. Standard JavaScript throughout:
// Store
app.memory.products = result.products;
// Read
const all = app.memory.products;
// Mutate
app.memory.products.push(newProduct);
app.memory.products.splice(0, 1);
// Delete a key
delete app.memory.products;
// Check if a key exists
"products" in app.memory;
// List all keys
Object.keys(app.memory);
// Clear everything
Object.keys(app.memory).forEach(k => delete app.memory[k]);
π‘ Load once, paginate from memoryΒΆ
The most common pattern. Fetch the full dataset once, then slice it on demand without re-fetching:
async function loadStore(context) {
const result = await context.fetch("/api/products");
app.memory.products = result.products;
app.memory.currentPage = 0;
context.data({
visibleProducts: app.memory.products.slice(0, 40)
});
}
function nextPage(context) {
const page = (app.memory.currentPage || 0) + 1;
app.memory.currentPage = page;
context.data({
visibleProducts: app.memory.products.slice(page * 40, (page + 1) * 40)
});
}
function prevPage(context) {
const page = Math.max(0, (app.memory.currentPage || 0) - 1);
app.memory.currentPage = page;
context.data({
visibleProducts: app.memory.products.slice(page * 40, (page + 1) * 40)
});
}
The full catalogue never touches the binding engine. Only the current page slice does.
π‘ Session and auth stateΒΆ
Good for data that is not UI state but needs to be accessible everywhere across the app:
// After login
app.memory.session = {
token: result.token,
userId: result.userId,
role: result.role
};
// Any page, any action
function loadAdminPanel(context) {
if (app.memory.session.role !== "admin") {
context.navigate("home");
return;
}
// ...
}
β οΈ Memory is not bindableΒΆ
{memory.products} in HTML does not work. app.memory is not in the binding engineβs resolution chain. It resolves to "" and logs [CLERA:BINDING_UNRESOLVED] in dev mode.
<!-- does not work -->
<p>{memory.products.length} items</p>
<!-- correct: move the value into data first -->
<p>{productCount} items</p>
context.data({ productCount: app.memory.products.length });
π What to store whereΒΆ
Data |
Store in |
Reason |
|---|---|---|
Full API datasets |
|
Too large for the binding engine |
Cached results used across pages |
|
Survives navigation |
Session and auth state |
|
Global, not UI |
What is visible on screen right now |
|
Page-scoped, needs binding |
Small global UI state (user, theme) |
|
Small, shared, needs binding |
Page-local filters or view state |
|
Scoped, needs binding |