All Articles

Blazor State Management Part III - Cascading Parameters

This article explores cascading values in Blazor 0.7.0

The source code for this article can be found here

This article is part of a Blazor state management exploration series.

  1. Blazor State Management Part I - Data-Binding
  2. Blazor State Management Part II - Event Delegation
  3. Blazor State Management Part III - Cascading Parameters

The last article ended with a question. How do we share data within the following component structure?

Cascading parameters.

With event delegation, we could update middle components to accept a person parameter and pass it through to child components that need it. We would also need to pass event handlers through the middle components. A doable, but a messy and cumbersome process.

Ideally, we would pass parameters from the parent component directly to child components that need them, no matter how nested the child components are. Well, it turns out, we can. CascadingValue is a unique tag that allows us to hoist parameters for child components, even nested ones, to acccess. This should feel familiar to anyone who has used React context.

Let’s create a MiddleComponent to contain the DisplayPerson and UpdatePerson components.

@* MiddleComponent.cshtml *@
<div class="boxed">
    <h4>DisplayPerson Component</h4>
    <DisplayPerson></DisplayPerson3>
</div>
<div class="boxed">
    <h4>UpdatePerson Componet</h4>
    <UpdatePerson></UpdatePerson3>
</div>

Notice that we are no longer passing parameters to DisplayPerson or UpdatePerson. This is because the components will check the hoisted space for the values instead of receiving them directly as parameters. Update index.cshtml to use the newly created MiddleComponent.

@* index.cshtml *@
...
<MiddleComponent></MiddleComponent>

@functions {
    protected Person person { get; set; } = new Person { Name = "Derek" };
    ...
}

This will not work. Remember, DisplayPerson and UpdatePerson need a Person object to work with. So let’s wrap MiddleComponent in a CascadingValue component to hoist our person object.

@* index.cshtml *@
...
<CascadingValue Value="@person">
 	<MiddleComponent></MiddleComponent>
</CascadingValue>
...

This is still not enough. UpdatePerson also expects a function parameter. A function that will handle updating the state when necessary. Each CascadingValue can only hoist one value so we will need to nest tags.

@* index.cshtml *@
<CascadingValue Value="@person">
    <CascadingValue 
        Value="@HandleChange" 
        Name="HandleChange" 
        T="Action<UIChangeEventArgs>">
        <MiddleComponent></MiddleComponent>
    </CascadingValue>
</CascadingValue>

@functions {
    protected Person person { get; set; } = new Person { Name = "Derek" };
    protected void HandleChange (UIChangeEventArgs e)
    {
        person.Name = e.Value.ToString();
        StateHasChanged();
    }
}

The second CascadingValue component is hoisting a named parameter. Since the parameter is a method, we need to help Blazor identify the parameter type by specifying the type with the T parameter.

Next, we need to update UpdatePerson and DisplayPerson to use CascadingParameters instead of normal parameters. We only need to update the decorators to specify CascadingParameters. Nothing else needs to change.

@* UpdatePerson.cshtml *@
...
@functions {
    [CascadingParameter] 
    protected Person person { get; set; }
    [CascadingParameter(Name = "HandleChange")] 
    protected Action<UIChangeEventArgs> CustomOnChange { get; set; }
    ...
}
@* DisplayPerson.cshtml *@
...
@functions {
    [CascadingParameter] protected Person person { get; set; }
}

Our application should work as it did at the end of the event delegation article. Updating the person’s name using the input field should update the name displayed in all components.


Conclusion

Yes, it is possible to use cascading parameters to share state throughout an application, but it is messy. The Blazor docs use CSS style rules or theme information as an example for using cascading parameters. read-only UI state or theme information are good candidates for cascading parameters. Otherwise, not only do the values need to be cascaded but so do the methods that will be responsible for updating the hoisted values. Not to mention, CascadingValue can only hoist one value at a time, requiring nested tags for each cascading value.