Every widget on a BESPA page is drawn on the initial request. On subsequent state changes the framework only re-renders widgets that have opted in by calling RedrawIfChanged (or RedrawIf, RedrawIfEq, or a sibling). Picking the right set is the single most useful skill in BESPA.
A widget needs RedrawIfChanged(r, "x") if and only if its rendered output depends on the state variable x. Output here means the bytes the widget writes — not just visible text, but href, value, class, hidden/shown state, and child content.
The classic case: a widget displays a state value, hides itself based on a state value, or computes its own href from a state value.
// HeadlineMedium depends on state.name. Redraw it whenever name changes.
wf.HeadlineMedium("Hello, ", state.Get("name"), "!").
HideIfEmpty(r, "name").
RedrawIfChanged(r, "name"),
// InputText posts back to the same state.name. DO NOT redraw it —
// re-rendering the <input> mid-typing loses the cursor focus.
wf.Form().Add(
wf.InputText("name", "").WithAutoSubmit(true),
),
Both HideIfEmpty and the inline state.Get reads in the children list make this widget depend on name. The RedrawIfChanged makes the redraw happen.
A button whose href encodes the next state — like a counter that increments — needs RedrawIfChanged just as much as the heading that displays the count:
// A button whose href encodes the next count value depends on state.count.
// Without RedrawIfChanged, the button keeps pointing at a stale URL.
wf.ButtonFilled("").Add("+").
WithHref("?count=" + strconv.Itoa(count+1)).
RedrawIfChanged(r, "count"),
Without it, clicking the button once works, but clicking it a second time would jump to the same value because the href was never recomputed.
An InputText posts its current value back via the form. If you redraw the input itself when its state variable changes, the browser replaces the live <input> element and the cursor jumps to position 0 mid-typing. Wrap the input in a Form with WithAutoSubmit(true) and let the dependent widgets (heading, derived values) redraw — the input itself stays mounted.
If nothing about a widget’s rendered output references state, leave RedrawIfChanged off. Static prose, headings, and chrome like an AppBar usually fall here:
// Pure presentation: text never changes. Don't add RedrawIfChanged.
wf.AppBar("Counter"),
wf.HeadlineLarge("Welcome"),
"Choose a number using the buttons below.",
Adding RedrawIfChanged on these wastes bytes — the framework dutifully re-emits identical HTML and the client swaps it in for nothing.
Basics → Incremental updates — the underlying mechanism that makes RedrawIfChanged work.
Showcase → Data table — a worked example with many widgets depending on the same state.