From 00bd0b75d3b5c6439519affd8c71a93d18efed25 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 19 Jan 2023 12:50:37 -0600 Subject: [PATCH] Rendering article internal versioning --- aspnetcore/blazor/components/rendering.md | 342 +++------------------- 1 file changed, 36 insertions(+), 306 deletions(-) diff --git a/aspnetcore/blazor/components/rendering.md b/aspnetcore/blazor/components/rendering.md index 9c0cc13955d8..a83c403e4f17 100644 --- a/aspnetcore/blazor/components/rendering.md +++ b/aspnetcore/blazor/components/rendering.md @@ -12,8 +12,6 @@ uid: blazor/components/rendering This article explains Razor component rendering in ASP.NET Core Blazor apps, including when to call to manually trigger a component to render. -:::moniker range=">= aspnetcore-7.0" - Components *must* render when they're first added to the component hierarchy by a parent component. This is the only time that a component must render. Components *may* render at other times according to their own logic and conventions. ## Rendering conventions for `ComponentBase` @@ -49,115 +47,29 @@ Even if is `Pages/ControlRender.razor`: -:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: - -For more information on performance best practices pertaining to , see . - -## When to call `StateHasChanged` - -Calling allows you to trigger a render at any time. However, be careful not to call unnecessarily, which is a common mistake that imposes unnecessary rendering costs. - -Code shouldn't need to call when: - -* Routinely handling events, whether synchronously or asynchronously, since triggers a render for most routine event handlers. -* Implementing typical lifecycle logic, such as [`OnInitialized`](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) or [`OnParametersSetAsync`](xref:blazor/components/lifecycle#after-parameters-are-set-onparameterssetasync), whether synchronously or asynchronously, since triggers a render for typical lifecycle events. - -However, it might make sense to call in the cases described in the following sections of this article: - -* [An asynchronous handler involves multiple asynchronous phases](#an-asynchronous-handler-involves-multiple-asynchronous-phases) -* [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) -* [To render component outside the subtree that is rerendered by a particular event](#to-render-a-component-outside-the-subtree-thats-rerendered-by-a-particular-event) - -### An asynchronous handler involves multiple asynchronous phases - -Due to the way that tasks are defined in .NET, a receiver of a can only observe its final completion, not intermediate asynchronous states. Therefore, can only trigger rerendering when the is first returned and when the finally completes. The framework can't know to rerender a component at other intermediate points, such as when an [returns data in a series of intermediate `Task`s](https://github.com/dotnet/aspnetcore/issues/43098#issuecomment-1206224427). If you want to rerender at intermediate points, call at those points. - -Consider the following `CounterState1` component, which updates the count four times on each click: - -* Automatic renders occur after the first and last increments of `currentCount`. -* Manual renders are triggered by calls to when the framework doesn't automatically trigger rerenders at intermediate processing points where `currentCount` is incremented. - -`Pages/CounterState1.razor`: - -:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: - -### Receiving a call from something external to the Blazor rendering and event handling system - - only knows about its own lifecycle methods and Blazor-triggered events. doesn't know about other events that may occur in code. For example, any C# events raised by a custom data store are unknown to Blazor. In order for such events to trigger rerendering to display updated values in the UI, call . - -Consider the following `CounterState2` component that uses to update a count at a regular interval and calls to update the UI: - -* `OnTimerCallback` runs outside of any Blazor-managed rendering flow or event notification. Therefore, `OnTimerCallback` must call because Blazor isn't aware of the changes to `currentCount` in the callback. -* The component implements , where the is disposed when the framework calls the `Dispose` method. For more information, see . - -Because the callback is invoked outside of Blazor's synchronization context, the component must wrap the logic of `OnTimerCallback` in to move it onto the renderer's synchronization context. This is equivalent to marshalling to the UI thread in other UI frameworks. can only be called from the renderer's synchronization context and throws an exception otherwise: - -> :::no-loc text="System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'"::: - -`Pages/CounterState2.razor`: - -:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: - -### To render a component outside the subtree that's rerendered by a particular event - -The UI might involve: - -1. Dispatching an event to one component. -1. Changing some state. -1. Rerendering a completely different component that isn't a descendant of the component receiving the event. - -One way to deal with this scenario is to provide a *state management* class, often as a dependency injection (DI) service, injected into multiple components. When one component calls a method on the state manager, the state manager raises a C# event that's then received by an independent component. - -For approaches to manage state, see the following resources: - -* [In-memory state container service (Blazor Server)](xref:blazor/state-management?pivots=server#in-memory-state-container-service-server) ([Blazor WebAssembly equivalent](xref:blazor/state-management?pivots=webassembly#in-memory-state-container-service-server)) section of the *State management* article. -* [Pass data across a component hierarchy](xref:blazor/components/cascading-values-and-parameters#pass-data-across-a-component-hierarchy) using cascading values and parameters. -* [Bind across more than two components](xref:blazor/components/data-binding#bind-across-more-than-two-components) using data bindings. - -For the state manager approach, C# events are outside the Blazor rendering pipeline. Call on other components you wish to rerender in response to the state manager's events. - -The state manager approach is similar to the earlier case with in the [previous section](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system). Since the execution call stack typically remains on the renderer's synchronization context, calling isn't normally required. Calling is only required if the logic escapes the synchronization context, such as calling on a or awaiting a with [`ConfigureAwait(false)`](xref:System.Threading.Tasks.Task.ConfigureAwait%2A). For more information, see the [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) section. - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - -Components *must* render when they're first added to the component hierarchy by a parent component. This is the only time that a component must render. Components *may* render at other times according to their own logic and conventions. - -## Rendering conventions for `ComponentBase` - -By default, Razor components inherit from the base class, which contains logic to trigger rerendering at the following times: +::: moniker range=">= aspnetcore-7.0" -* After applying an updated set of [parameters](xref:blazor/components/data-binding#binding-with-component-parameters) from a parent component. -* After applying an updated value for a [cascading parameter](xref:blazor/components/cascading-values-and-parameters). -* After notification of an event and invoking one of its own [event handlers](xref:blazor/components/event-handling). -* After a call to its own method (see ). For guidance on how to prevent overwriting child component parameters when is called in a parent component, see . +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: -Components inherited from skip rerenders due to parameter updates if either of the following are true: +::: moniker-end -* All of the parameters are from a set of known types† or any [primitive type](/dotnet/api/system.type.isprimitive) that hasn't changed since the previous set of parameters were set. +::: moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - †The Blazor framework uses a set of built-in rules and explicit parameter type checks for change detection. These rules and the types are subject to change at any time. For more information, see the [`ChangeDetection` API in the ASP.NET Core reference source](https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/ChangeDetection.cs). - - [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] +:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: -* The component's [`ShouldRender` method](#suppress-ui-refreshing-shouldrender) returns `false`. +::: moniker-end -## Control the rendering flow - -In most cases, conventions result in the correct subset of component rerenders after an event occurs. Developers aren't usually required to provide manual logic to tell the framework which components to rerender and when to rerender them. The overall effect of the framework's conventions is that the component receiving an event rerenders itself, which recursively triggers rerendering of descendant components whose parameter values may have changed. +::: moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" -For more information on the performance implications of the framework's conventions and how to optimize an app's component hierarchy for rendering, see . - -## Suppress UI refreshing (`ShouldRender`) +:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: - is called each time a component is rendered. Override to manage UI refreshing. If the implementation returns `true`, the UI is refreshed. +::: moniker-end -Even if is overridden, the component is always initially rendered. +::: moniker range="< aspnetcore-5.0" -`Pages/ControlRender.razor`: +:::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: -:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: +::: moniker-end For more information on performance best practices pertaining to , see . @@ -187,119 +99,29 @@ Consider the following `CounterState1` component, which updates the count four t `Pages/CounterState1.razor`: -:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: - -### Receiving a call from something external to the Blazor rendering and event handling system - - only knows about its own lifecycle methods and Blazor-triggered events. doesn't know about other events that may occur in code. For example, any C# events raised by a custom data store are unknown to Blazor. In order for such events to trigger rerendering to display updated values in the UI, call . - -Consider the following `CounterState2` component that uses to update a count at a regular interval and calls to update the UI: - -* `OnTimerCallback` runs outside of any Blazor-managed rendering flow or event notification. Therefore, `OnTimerCallback` must call because Blazor isn't aware of the changes to `currentCount` in the callback. -* The component implements , where the is disposed when the framework calls the `Dispose` method. For more information, see . - -Because the callback is invoked outside of Blazor's synchronization context, the component must wrap the logic of `OnTimerCallback` in to move it onto the renderer's synchronization context. This is equivalent to marshalling to the UI thread in other UI frameworks. can only be called from the renderer's synchronization context and throws an exception otherwise: - -> :::no-loc text="System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'"::: - -`Pages/CounterState2.razor`: - -:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: - -### To render a component outside the subtree that's rerendered by a particular event - -The UI might involve: - -1. Dispatching an event to one component. -1. Changing some state. -1. Rerendering a completely different component that isn't a descendant of the component receiving the event. - -One way to deal with this scenario is to provide a *state management* class, often as a dependency injection (DI) service, injected into multiple components. When one component calls a method on the state manager, the state manager raises a C# event that's then received by an independent component. - -For approaches to manage state, see the following resources: - -* [In-memory state container service (Blazor Server)](xref:blazor/state-management?pivots=server#in-memory-state-container-service-server) ([Blazor WebAssembly equivalent](xref:blazor/state-management?pivots=webassembly#in-memory-state-container-service-server)) section of the *State management* article. -* [Pass data across a component hierarchy](xref:blazor/components/cascading-values-and-parameters#pass-data-across-a-component-hierarchy) using cascading values and parameters. -* [Bind across more than two components](xref:blazor/components/data-binding#bind-across-more-than-two-components) using data bindings. - -For the state manager approach, C# events are outside the Blazor rendering pipeline. Call on other components you wish to rerender in response to the state manager's events. - -The state manager approach is similar to the earlier case with in the [previous section](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system). Since the execution call stack typically remains on the renderer's synchronization context, calling isn't normally required. Calling is only required if the logic escapes the synchronization context, such as calling on a or awaiting a with [`ConfigureAwait(false)`](xref:System.Threading.Tasks.Task.ConfigureAwait%2A). For more information, see the [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) section. - -:::moniker-end - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -Components *must* render when they're first added to the component hierarchy by a parent component. This is the only time that a component must render. Components *may* render at other times according to their own logic and conventions. - -## Rendering conventions for `ComponentBase` - -By default, Razor components inherit from the base class, which contains logic to trigger rerendering at the following times: - -* After applying an updated set of [parameters](xref:blazor/components/data-binding#binding-with-component-parameters) from a parent component. -* After applying an updated value for a [cascading parameter](xref:blazor/components/cascading-values-and-parameters). -* After notification of an event and invoking one of its own [event handlers](xref:blazor/components/event-handling). -* After a call to its own method (see ). For guidance on how to prevent overwriting child component parameters when is called in a parent component, see . - -Components inherited from skip rerenders due to parameter updates if either of the following are true: - -* All of the parameters are from a set of known types† or any [primitive type](/dotnet/api/system.type.isprimitive) that hasn't changed since the previous set of parameters were set. - - †The Blazor framework uses a set of built-in rules and explicit parameter type checks for change detection. These rules and the types are subject to change at any time. For more information, see the [`ChangeDetection` API in the ASP.NET Core reference source](https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/ChangeDetection.cs). - - [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] - -* The component's [`ShouldRender` method](#suppress-ui-refreshing-shouldrender) returns `false`. - -Blazor's framework uses a set of built-in rules for change detection, which are subject to change at any time. For more information, see the [`ChangeDetection` API in the ASP.NET Core reference source](https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/ChangeDetection.cs). +::: moniker range=">= aspnetcore-7.0" -[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] - -## Control the rendering flow - -In most cases, conventions result in the correct subset of component rerenders after an event occurs. Developers aren't usually required to provide manual logic to tell the framework which components to rerender and when to rerender them. The overall effect of the framework's conventions is that the component receiving an event rerenders itself, which recursively triggers rerendering of descendant components whose parameter values may have changed. - -For more information on the performance implications of the framework's conventions and how to optimize an app's component hierarchy for rendering, see . - -## Suppress UI refreshing (`ShouldRender`) - - is called each time a component is rendered. Override to manage UI refreshing. If the implementation returns `true`, the UI is refreshed. - -Even if is overridden, the component is always initially rendered. - -`Pages/ControlRender.razor`: - -:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: -For more information on performance best practices pertaining to , see . +::: moniker-end -## When to call `StateHasChanged` +::: moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" -Calling allows you to trigger a render at any time. However, be careful not to call unnecessarily, which is a common mistake that imposes unnecessary rendering costs. +:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: -Code shouldn't need to call when: +::: moniker-end -* Routinely handling events, whether synchronously or asynchronously, since triggers a render for most routine event handlers. -* Implementing typical lifecycle logic, such as [`OnInitialized`](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) or [`OnParametersSetAsync`](xref:blazor/components/lifecycle#after-parameters-are-set-onparameterssetasync), whether synchronously or asynchronously, since triggers a render for typical lifecycle events. +::: moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" -However, it might make sense to call in the cases described in the following sections of this article: - -* [An asynchronous handler involves multiple asynchronous phases](#an-asynchronous-handler-involves-multiple-asynchronous-phases) -* [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) -* [To render component outside the subtree that is rerendered by a particular event](#to-render-a-component-outside-the-subtree-thats-rerendered-by-a-particular-event) +:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: -### An asynchronous handler involves multiple asynchronous phases +::: moniker-end -Due to the way that tasks are defined in .NET, a receiver of a can only observe its final completion, not intermediate asynchronous states. Therefore, can only trigger rerendering when the is first returned and when the finally completes. The framework can't know to rerender a component at other intermediate points, such as when an [returns data in a series of intermediate `Task`s](https://github.com/dotnet/aspnetcore/issues/43098#issuecomment-1206224427). If you want to rerender at intermediate points, call at those points. - -Consider the following `CounterState1` component, which updates the count four times on each click: +::: moniker range="< aspnetcore-5.0" -* Automatic renders occur after the first and last increments of `currentCount`. -* Manual renders are triggered by calls to when the framework doesn't automatically trigger rerenders at intermediate processing points where `currentCount` is incremented. +:::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: -`Pages/CounterState1.razor`: - -:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: +::: moniker-end ### Receiving a call from something external to the Blazor rendering and event handling system @@ -316,120 +138,30 @@ Because the callback is invoked outside of Blazor's synchronization context, the `Pages/CounterState2.razor`: -:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: - -### To render a component outside the subtree that's rerendered by a particular event - -The UI might involve: - -1. Dispatching an event to one component. -1. Changing some state. -1. Rerendering a completely different component that isn't a descendant of the component receiving the event. - -One way to deal with this scenario is to provide a *state management* class, often as a dependency injection (DI) service, injected into multiple components. When one component calls a method on the state manager, the state manager raises a C# event that's then received by an independent component. - -For approaches to manage state, see the following resources: - -* [In-memory state container service (Blazor Server)](xref:blazor/state-management?pivots=server#in-memory-state-container-service-server) ([Blazor WebAssembly equivalent](xref:blazor/state-management?pivots=webassembly#in-memory-state-container-service-server)) section of the *State management* article. -* [Pass data across a component hierarchy](xref:blazor/components/cascading-values-and-parameters#pass-data-across-a-component-hierarchy) using cascading values and parameters. -* [Bind across more than two components](xref:blazor/components/data-binding#bind-across-more-than-two-components) using data bindings. - -For the state manager approach, C# events are outside the Blazor rendering pipeline. Call on other components you wish to rerender in response to the state manager's events. - -The state manager approach is similar to the earlier case with in the [previous section](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system). Since the execution call stack typically remains on the renderer's synchronization context, calling isn't normally required. Calling is only required if the logic escapes the synchronization context, such as calling on a or awaiting a with [`ConfigureAwait(false)`](xref:System.Threading.Tasks.Task.ConfigureAwait%2A). For more information, see the [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) section. - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -Components *must* render when they're first added to the component hierarchy by a parent component. This is the only time that a component must render. Components *may* render at other times according to their own logic and conventions. - -## Rendering conventions for `ComponentBase` +::: moniker range=">= aspnetcore-7.0" -By default, Razor components inherit from the base class, which contains logic to trigger rerendering at the following times: - -* After applying an updated set of [parameters](xref:blazor/components/data-binding#binding-with-component-parameters) from a parent component. -* After applying an updated value for a [cascading parameter](xref:blazor/components/cascading-values-and-parameters). -* After notification of an event and invoking one of its own [event handlers](xref:blazor/components/event-handling). -* After a call to its own method (see ). For guidance on how to prevent overwriting child component parameters when is called in a parent component, see . - -Components inherited from skip rerenders due to parameter updates if either of the following are true: - -* All of the parameters are from a set of known types† or any [primitive type](/dotnet/api/system.type.isprimitive) that hasn't changed since the previous set of parameters were set. - - †The Blazor framework uses a set of built-in rules and explicit parameter type checks for change detection. These rules and the types are subject to change at any time. For more information, see the [`ChangeDetection` API in the ASP.NET Core reference source](https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/ChangeDetection.cs). - - [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] - -* The component's [`ShouldRender` method](#suppress-ui-refreshing-shouldrender) returns `false`. - -Blazor's framework uses a set of built-in rules for change detection, which are subject to change at any time. For more information, see the [`ChangeDetection` API in the ASP.NET Core reference source](https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/ChangeDetection.cs). - -[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] - -## Control the rendering flow - -In most cases, conventions result in the correct subset of component rerenders after an event occurs. Developers aren't usually required to provide manual logic to tell the framework which components to rerender and when to rerender them. The overall effect of the framework's conventions is that the component receiving an event rerenders itself, which recursively triggers rerendering of descendant components whose parameter values may have changed. - -For more information on the performance implications of the framework's conventions and how to optimize an app's component hierarchy for rendering, see . - -## Suppress UI refreshing (`ShouldRender`) - - is called each time a component is rendered. Override to manage UI refreshing. If the implementation returns `true`, the UI is refreshed. - -Even if is overridden, the component is always initially rendered. - -`Pages/ControlRender.razor`: - -:::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/rendering/ControlRender.razor"::: - -For more information on performance best practices pertaining to , see . - -## When to call `StateHasChanged` - -Calling allows you to trigger a render at any time. However, be careful not to call unnecessarily, which is a common mistake that imposes unnecessary rendering costs. - -Code shouldn't need to call when: - -* Routinely handling events, whether synchronously or asynchronously, since triggers a render for most routine event handlers. -* Implementing typical lifecycle logic, such as [`OnInitialized`](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) or [`OnParametersSetAsync`](xref:blazor/components/lifecycle#after-parameters-are-set-onparameterssetasync), whether synchronously or asynchronously, since triggers a render for typical lifecycle events. - -However, it might make sense to call in the cases described in the following sections of this article: - -* [An asynchronous handler involves multiple asynchronous phases](#an-asynchronous-handler-involves-multiple-asynchronous-phases) -* [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) -* [To render component outside the subtree that is rerendered by a particular event](#to-render-a-component-outside-the-subtree-thats-rerendered-by-a-particular-event) - -### An asynchronous handler involves multiple asynchronous phases - -Due to the way that tasks are defined in .NET, a receiver of a can only observe its final completion, not intermediate asynchronous states. Therefore, can only trigger rerendering when the is first returned and when the finally completes. The framework can't know to rerender a component at other intermediate points, such as when an [returns data in a series of intermediate `Task`s](https://github.com/dotnet/aspnetcore/issues/43098#issuecomment-1206224427). If you want to rerender at intermediate points, call at those points. - -Consider the following `CounterState1` component, which updates the count four times on each click: - -* Automatic renders occur after the first and last increments of `currentCount`. -* Manual renders are triggered by calls to when the framework doesn't automatically trigger rerenders at intermediate processing points where `currentCount` is incremented. +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: -`Pages/CounterState1.razor`: +::: moniker-end -:::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/rendering/CounterState1.razor" highlight="17,21,25,29"::: +::: moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" -### Receiving a call from something external to the Blazor rendering and event handling system +:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: - only knows about its own lifecycle methods and Blazor-triggered events. doesn't know about other events that may occur in code. For example, any C# events raised by a custom data store are unknown to Blazor. In order for such events to trigger rerendering to display updated values in the UI, call . +::: moniker-end -Consider the following `CounterState2` component that uses to update a count at a regular interval and calls to update the UI: +::: moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" -* `OnTimerCallback` runs outside of any Blazor-managed rendering flow or event notification. Therefore, `OnTimerCallback` must call because Blazor isn't aware of the changes to `currentCount` in the callback. -* The component implements , where the is disposed when the framework calls the `Dispose` method. For more information, see . +:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: -Because the callback is invoked outside of Blazor's synchronization context, the component must wrap the logic of `OnTimerCallback` in to move it onto the renderer's synchronization context. This is equivalent to marshalling to the UI thread in other UI frameworks. can only be called from the renderer's synchronization context and throws an exception otherwise: +::: moniker-end -> :::no-loc text="System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'"::: - -`Pages/CounterState2.razor`: +::: moniker range="< aspnetcore-5.0" :::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/rendering/CounterState2.razor" highlight="26"::: +::: moniker-end + ### To render a component outside the subtree that's rerendered by a particular event The UI might involve: @@ -449,5 +181,3 @@ For approaches to manage state, see the following resources: For the state manager approach, C# events are outside the Blazor rendering pipeline. Call on other components you wish to rerender in response to the state manager's events. The state manager approach is similar to the earlier case with in the [previous section](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system). Since the execution call stack typically remains on the renderer's synchronization context, calling isn't normally required. Calling is only required if the logic escapes the synchronization context, such as calling on a or awaiting a with [`ConfigureAwait(false)`](xref:System.Threading.Tasks.Task.ConfigureAwait%2A). For more information, see the [Receiving a call from something external to the Blazor rendering and event handling system](#receiving-a-call-from-something-external-to-the-blazor-rendering-and-event-handling-system) section. - -:::moniker-end