Skip to content

Add a section on cascading values/parameters for state management with multiple subscribers #34236

@hakenr

Description

@hakenr

Description

I think the Factor out the state preservation to a common location section has some issues that make it incomplete or problematic:

  1. Prerendering Issue:
    The provided example fails during prerendering because ProtectedSessionStore.GetAsync cannot be invoked from OnInitialized. To fix this, prerendering must be disabled for the example to function correctly. See this code. A possible solution is changing the render mode to something like new InteractiveServerRenderMode(prerender: false).

  2. Issue with Multiple Subscribers:
    The CounterStateProvider fails when more than one component subscribes to [CascadingParameter] private CounterStateProvider? CounterStateProvider. The cascading value in this case is the CounterStateProvider component instance (this), which doesn't change after being set (you could even set IsFixed="true"). Since the actual counter value (CurrentCount) changes internally, the CascadingValue component is not being re-rendered (allowing the new value to be distributed to subscribers) and updates to CurrentCount are not propagated to other components subscribed to the cascading value. (The only situation when CascadingValue component notifies the subscribers of changes is when the CascadingValue itself receives new parameters in SetParametersAsync.)

    Steps to Reproduce:

    • Follow the documentation steps, fixing the prerendering issue as mentioned above.
    • Create a new SubCounter.razor component, duplicating the content of Counter.razor but without the @page directive.
    • Add <SubCounter /> to Counter.razor so both components render simultaneously.
    • Test the two Increment buttons (one in Counter.razor and the other in SubCounter.razor). You'll notice that updating the counter in one component doesn't trigger updates in the other.

    Screenshot of the issue

    The current implementation of CounterStateProvider doesn't include a mechanism to notify subscribers about state changes. Without such notifications, this approach is effectively just another way to inject a service into components. If the intent is to use cascading values/parameters for proper state management, the "state" (e.g., CurrentCount) should be the cascading value distributed, not the "provider" (e.g., the CounterStateProvider component).

    Suggestion for Improvement:
    To use cascading values/parameters effectively for state management, we could use CascadingValueSource<T>. This pattern is used in Blazor's built-in AuthenticationStateProvider, as seen in the AuthenticationStateCascadingValueSource implementation. By propagating the actual state (CurrentCount) rather than the provider, changes would trigger proper re-renders of subscribed components.

(I can try proposing new content using the CascadingValueSource, but it'll probably take some time to prepare since I'm pretty busy with other projects right now.)

Page URL

https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-9.0&pivots=server

Content source URL

https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/blazor/state-management.md

Document ID

e5e1273b-195e-5da1-b4aa-66bbcff1425b

Article author

@guardrex

Related Issues

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions