dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.4k stars 10k forks source link

Provide a way to directly pass new parameters to a rendered component (Blazor) #49016

Open egil opened 1 year ago

egil commented 1 year ago

Background and Motivation

In bUnit and other custom renderers for Blazor there may be a need to pass new parameters to a rendered component directly, perhaps because the component is a "root" component and has no parent component that can be used to pass new parameters to it via the normal render tree method.

The (internal, public in .NET 8) ComponentState type has a SetDirectParameters method that is internal, but should be used instead of calling the public IComponent.SetParametersAsync directly for all internal states in the Renderer and related types to be updated correctly (I assume).

In addition to this, it will be beneficial if the Renderer would enter into "batch mode" like it does when new parameters are passed from a parent component to a child component. This batches up synchronous re-renders.

Proposed API

The suggestion is to add a protected void SetDirectParameters(int componentId, ParameterView parameters) method to Renderer. It is likely only useful for custom renderers that inherit from Renderer, hence there is no reason for this to be public.

This method should also toggle "batch render mode" on before passing the new parameters to the component, ensuring re-render, after the new parameters are set, behaves in a similar way as if the parameters were passed to the component from a parent component.

namespace Microsoft.AspNetCore.Components.RenderTree
{
    public abstract class Renderer : IDisposable
    {
+        protected void SetDirectParameters(int componentId, ParameterView parameters);
    }
}

Alternative Designs

Make the ComponentState.SetDirectParameters method public. See #48980.

Risks

More public APIs that the team has to support and may limit their abilities to change things in the future.

Notes

In bUnit, we are planning to do this via reflection instead of calling IComponent.SetParametersAsync going forward.

Our version of the SetDirectParameters(int componentId, ParameterView parameters) method is doing the following:

  1. Set _isBatchInProgress = true
  2. Call var state = GetRequiredComponentState(componentId)
  3. Call state.SetDirectParameters(parameters), catching any exceptions thrown by the method passing an exception to HandleException.
  4. Set _isBatchInProgress = false regardless of the outcome of state.SetDirectParameters.
  5. Call ProcessPendingRender() method.
ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost commented 11 months ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.