Search code examples
c#.netasp.net-corerazorblazor

Changing property in Razor @ref component does not update its usage in HTML element


Beginner at Blazor here.

I have this very simple Razor component that has a property named Paragraph which is being used by the HTML <p> element:

<p>@Paragraph</p>
@code {
    public string Paragraph { get; set; } = "initial value";
}

In a parent component, I use this component (named Foo) and change the Paragraph property in OnAfterRender:

<Foo @ref="_foo" />

@code {
    private Foo? _foo;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            if (_foo is not null)
            {
                _foo.Paragraph = "Changed";
            }
        }
    }
}

However, this doesn't really do anything; I still see the paragraph 'initial value' and not 'Changed'. In fact, the line of code _foo.Paragraph = "Changed"; does execute, but I don't really see anything being changed.

I also tried to invoke the StateHasChanged() method on the parent element after changing the Paragraph property but it didn't really change anything.

Is there a technical reason on why the paragraph doesn't change to Changed? I've seen numerous similar questions but haven't found a solution that solves my problem.


Solution

  • The parent just has <Foo @ref="_foo" />, note that there are no parameters. Blazor will re-render child components when parameters (might) have changed.

    I also tried to invoke the StateHasChanged() - that comes close but it will only re-render the parent, not the Foo component.

    Since StateHasChanged() is protected you can't call it directly so you'll have to add a method to Foo and use it like:

       if (firstRender)
        {
            if (_foo is not null)
            {
                _foo.Paragraph = "Changed";
                _foo.DoStateHasChanged();
            }
        }
    

    But of course the use of @ref is not advisable here, prefer <Foo Paragraph="@someText" />. That way both Parent and Child will only re-render when needed.