Skip to content
IzzyBlazor 0.1.0-alpha.17

Enter all results ↑ ↓ move Esc close

A value resets on the next request

A static page is built afresh for every request, so a field in the component starts over each time. Keep what the page needs in the address, or post it.

Problem

A value set in one request is gone in the next: a count goes back to its first value, a chosen step resets, a list loaded on the first visit is loaded again. Here every post shows 3 guests, however many times it's pressed; on an interactive page the same code counts up.

Booking.razor
<form method="post" @formname="guests" @onsubmit="() => _guests++">
    <AntiforgeryToken />
    <Button Submit>Add a guest</Button>
</form>
<TextBlock>@_guests guests</TextBlock>

@code {
    private int _guests = 2;
}

Cause

On an interactive page a component instance lives as long as it stays on the page, so its fields keep their values. On a static page, each request (a link followed, a form posted, a reload) creates new components, renders them and throws them away. Nothing is kept on the server between requests unless you store it.

Fix

Keep the state where the next request carries it:

  • In the address. Read it with [SupplyParameterFromQuery], and make each change a link that sets it with NavigationManager.GetUriWithQueryParameter, which keeps the rest of the query string. It survives a reload, and the page can be shared or bookmarked as it is.
  • In the form. Fields post their values, and the page reads them with [SupplyParameterFromForm]. A value with no field of its own can post in a hidden <input>.
  • Elsewhere. A database on the server, or a cookie in the browser for a reader's preferences, read on each request.
Booking.razor
@inject NavigationManager Navigation

<Button Href="@Navigation.GetUriWithQueryParameter("guests", Guests + 1)">
    Add a guest
</Button>
<TextBlock>@Guests guests</TextBlock>

@code {
    [SupplyParameterFromQuery(Name = "guests")]
    private int? GuestsQuery { get; set; }

    private int Guests => GuestsQuery ?? 2;
}

Preview

3 guests

Code

StateInAddress.razor
@inject NavigationManager Navigation

<Row Gap="3" Align="Align.Center">
    <IconButton Icon="Lucide.Minus" Label="Fewer guests" Href="@To(Guests - 1)" Disabled="@(Guests <= Min)"
                Variant="ButtonVariant.Outline" Accent="Accent.Neutral" />
    <TextBlock Weight="FontWeight.Medium">@Guests @(Guests == 1 ? "guest" : "guests")</TextBlock>
    <IconButton Icon="Lucide.Plus" Label="More guests" Href="@To(Guests + 1)" Disabled="@(Guests >= Max)"
                Variant="ButtonVariant.Outline" Accent="Accent.Neutral" />
</Row>

@code {
    private const int Min = 1;
    private const int Max = 8;

    // The count lives in the address (?guests=3), so each request knows it. A field would start
    // over at every request on a static page.
    [SupplyParameterFromQuery(Name = "guests")]
    private int? GuestsQuery { get; set; }

    private int Guests => Math.Clamp(GuestsQuery ?? 2, Min, Max);

    private string To(int guests) => Navigation.GetUriWithQueryParameter("guests", guests);
}

Static: Each button is a link to this page with a new ?guests=, so every request knows the count.

IzzyBlazor's components use the address the same way: Table, Pagination and FilterForm keep their state in the query string, Tabs with a QueryKey opens the tab the address names, and a dialog opens from ?dialog=id.