Sharing Global State
Some UI state needs to be visible across multiple components on a screen — for example, a cart item count that appears in both the app bar and a floating checkout button. In RUF, this presents a challenge: the client cannot mutate SessionMeta directly, so how can the UI reflect optimistic changes before the server responds?
The problem
Consider a user tapping a "+" button to increase a product quantity. The action is dispatched to the server, but there may be a short delay before the response arrives. The user expects immediate feedback.
The naive solution would be to mutate meta.cartItemCount directly on the client. But this violates the protocol's core rule: only the server may mutate SessionMeta.
The state-holding component pattern
The solution is to introduce a dedicated component whose sole purpose is to hold shared state. Instead of storing shared state in meta, the server sends it as a component — and the client can update that component optimistically.
For example, a cart_quantities component might look like:
{
"rel": "cart_quantities",
"behavior": "VISIBLE",
"locale": {},
"payload": {
"totalItems": 3,
"totalPrice": 49.90
}
}
Any component on the screen that needs to display cart state reads from cart_quantities instead of from meta.
How optimistic updates work with this pattern
When the user taps "+" to add an item:
- The client dispatches the action to the server
- Optimistically, the client updates the
cart_quantitiescomponent in its local cache — incrementingtotalItemsby 1 and adjustingtotalPrice - The server responds with the authoritative
cart_quantitiescomponent - The client replaces its optimistic version with the server's confirmed version
If the server rejects the action, the client rolls back the optimistic component update — restoring the previous cache state.
Key insight
The rule is: the client derives all state from components, not from meta. Meta is for server-side decision making — it travels with every request so the server has full context. Components are for the client's rendering layer. Keeping these roles separate is what makes the pattern work.
When to use this pattern
Use a state-holding component when:
- Multiple components on the same screen need to display the same derived state
- That state may need to be updated optimistically
- The state changes as a result of user actions on that screen
If state only needs to be reflected after the server confirms (no optimistic update needed), no special pattern is required — the server simply updates the relevant components in its response.