Skip to main content

Built-In Navigation and Lifecycle

Overview​

Reservoir's built-in client features represent navigation and application milestones as actions and state. This gives pages and diagnostics the same explicit state model used by application features.

Registration​

All entry points extend IReservoirBuilder and are supplied by Mississippi.Reservoir.Client:

MethodRegisters
AddReservoirBlazorBuiltIns()Navigation and lifecycle features
AddBuiltInNavigation()Navigation state, location reducer, and navigation effect
AddBuiltInLifecycle()Lifecycle state and milestone reducers

Registration extensions live in Mississippi.Reservoir.Client.BuiltIn, .BuiltIn.Navigation, and .BuiltIn.Lifecycle. Navigation action types live in .BuiltIn.Navigation.Actions; lifecycle action types live in .BuiltIn.Lifecycle.Actions, while LifecycleState and LifecyclePhase live in .BuiltIn.Lifecycle.State. C# does not import child namespaces automatically. Spring startup registers both features inside its Reservoir callback.

Browser Location Observation​

Render one ReservoirNavigationProvider at the application root to connect NavigationManager.LocationChanged with the store. This is the root-markup pattern used by Spring:

@using Mississippi.Reservoir.Client.BuiltIn.Components

<ReservoirNavigationProvider/>

The provider dispatches the current URI on initialization, forwards subsequent location changes, and unsubscribes when disposed. Its initial notification contributes to NavigationCount; that count represents handled location notifications rather than only user clicks.

Before the provider's initial dispatch, or if no provider is rendered, registered NavigationState has CurrentUri = null, PreviousUri = null, IsNavigationIntercepted = false, and NavigationCount = 0. The initial dispatch records the current browser URI and increments the count to one.

The action namespace is Mississippi.Reservoir.Client.BuiltIn.Navigation.Actions.

ActionParameters and defaultsPurpose
NavigateActionUri, ForceLoad = falseNavigate through NavigationManager
ReplaceRouteActionUri, ForceLoad = falseNavigate while replacing the history entry
SetQueryParamsActionParameters, ReplaceHistory = trueUpdate query parameters on the current URI
ScrollToAnchorActionAnchorId without #, ReplaceHistory = falseNavigate to the current page's fragment
LocationChangedActionLocation, IsNavigationInterceptedRecord an observed browser location

Use these actions for application navigation. The effect accepts relative application paths and absolute URIs on the same origin; use normal links for external destinations. For a cross-origin absolute URI in NavigateAction or ReplaceRouteAction, the effect throws, but the store catches the effect failure. Dispatch returns without navigation or an error action, so do not wait for a location update or expect to catch that failure from Dispatch. Supported navigation follows Blazor's NavigationManager behavior, including history and force-load semantics.

NavigationState uses feature key reservoir:navigation and exposes CurrentUri, PreviousUri, IsNavigationIntercepted, and NavigationCount. The location reducer moves the current URI to previous, records the new URI/interception flag, and increments the count.

For SetQueryParamsAction, use Blazor's supported query values: bool, DateOnly, DateTime, decimal, double, float, Guid, int, long, and string, including their supported nullable and array forms. The Blazor navigation reference defines this contract. Validate values before dispatch: unsupported object types are rejected by Blazor, and the live effect boundary catches that exception without producing a navigation error action.

To remove an existing query parameter, include its key in SetQueryParamsAction.Parameters with a null value. Omitting the key preserves its current query value. This follows the same Blazor query-update contract used for additions and replacements.

Lifecycle Milestones​

LifecycleState uses feature key reservoir:lifecycle. It starts in NotStarted with null timestamps.

Application actionState update
AppInitAction(InitializedAt)Sets Phase = Initializing and InitializedAt
AppReadyAction(ReadyAt)Sets Phase = Ready and ReadyAt

The application dispatches these actions at the milestones it defines. Supply timestamps in the payload, using the application's time source. The reducers use those values directly, keeping the transition deterministic and easy to test. Each reducer updates the fields shown above and preserves the other fields.

Order and deduplicate lifecycle milestones in the application. The reducers apply each supplied phase and timestamp directly: AppInitAction after AppReadyAction returns the phase to Initializing while preserving ReadyAt, and repeated actions replace their corresponding timestamps.

Use lifecycle state to explain what initialization has completed, and give an AI assistant precise milestone actions and expected state when adding startup behavior.

Source and Verification​

Summary​

Observe navigation through the root provider and supply lifecycle milestones from application code. Both become explicit actions and state that pages, tests, and development tools can inspect.

Next Steps​