Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 99 additions & 3 deletions aspnetcore/blazor/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ description: Learn how to create and use Razor components, including how to bind
monikerRange: '>= aspnetcore-3.1'
ms.author: riande
ms.custom: mvc
ms.date: 03/25/2020
ms.date: 04/21/2020
no-loc: [Blazor, SignalR]
uid: blazor/components
---
# Create and use ASP.NET Core Razor components

By [Luke Latham](https://github.com/guardrex) and [Daniel Roth](https://github.com/danroth27)
By [Luke Latham](https://github.com/guardrex), [Daniel Roth](https://github.com/danroth27), and [Tobias Bartsch](https://www.aveo-solutions.com/)

[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/blazor/common/samples/) ([how to download](xref:index#how-to-download-a-sample))

Expand Down Expand Up @@ -134,6 +134,9 @@ In the following example from the sample app, the `ParentComponent` sets the val

[!code-razor[](components/samples_snapshot/ParentComponent.razor?highlight=5-6)]

> [!WARNING]
> Don't create components that write to their own *component parameters*, use a private field instead. For more information, see the [Don't create components that write to their own parameter properties](#dont-create-components-that-write-to-their-own-parameter-properties) section.

## Child content

Components can set the content of another component. The assigning component provides the content between the tags that specify the receiving component.
Expand Down Expand Up @@ -392,7 +395,7 @@ Consider the following example:

The contents of the `People` collection may change with inserted, deleted, or re-ordered entries. When the component rerenders, the `<DetailsEditor>` component may change to receive different `Details` parameter values. This may cause more complex rerendering than expected. In some cases, rerendering can lead to visible behavior differences, such as lost element focus.

The mapping process can be controlled with the `@key` directive attribute. `@key` causes the diffing algorithm to guarantee preservation of elements or components based on the key's value:
The mapping process can be controlled with the [`@key`](xref:mvc/views/razor#key) directive attribute. `@key` causes the diffing algorithm to guarantee preservation of elements or components based on the key's value:

```csharp
@foreach (var person in People)
Expand Down Expand Up @@ -446,6 +449,99 @@ Generally, it makes sense to supply one of the following kinds of value for `@ke

Ensure that values used for `@key` don't clash. If clashing values are detected within the same parent element, Blazor throws an exception because it can't deterministically map old elements or components to new elements or components. Only use distinct values, such as object instances or primary key values.

## Don't create components that write to their own parameter properties

Parameters are overwritten under the following conditions:

* A child component's content is rendered with a `RenderFragment`.
* <xref:Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged%2A> is called in the parent component.

Parameters are reset because the parent component rerenders when <xref:Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged%2A> is called and new parameter values are supplied to the child component.

Consider the following `Expander` component that:

* Renders child content.
* Toggles showing child content with a component parameter.

```razor
<div @onclick="@Toggle">
Toggle (Expanded = @Expanded)

@if (Expanded)
{
@ChildContent
}
</div>

@code {
[Parameter]
public bool Expanded { get; set; }

[Parameter]
public RenderFragment ChildContent { get; set; }

private void Toggle()
{
Expanded = !Expanded;
}
}
```

The `Expander` component is added to a parent component that may call `StateHasChanged`:

```razor
<Expander Expanded="true">
<h1>Hello, world!</h1>
</Expander>

<Expander Expanded="true" />

<button @onclick="@(() => StateHasChanged())">
Call StateHasChanged
</button>
```

Initially, the `Expander` components behave independently when their `Expanded` properties are toggled. The child components maintain their states as expected. When `StateHasChanged` is called in the parent, the `Expanded` parameter of the first child component is reset back to its initial value (`true`). The second `Expander` component's `Expanded` value isn't reset because no child content is rendered in the second component.

To maintain state in the preceding scenario, use a *private field* in the `Expander` component to maintain its toggled state.

The following `Expander` component:

* Accepts the `Expanded` component parameter value from the parent.
* Assigns the component parameter value to a *private field* (`_expanded`) in the [OnInitialized event](xref:blazor/lifecycle#component-initialization-methods).
* Uses the private field to maintain its internal toggle state.

```razor
<div @onclick="@Toggle">
Toggle (Expanded = @_expanded)

@if (_expanded)
{
@ChildContent
}
</div>

@code {
[Parameter]
public bool Expanded { get; set; }

[Parameter]
public RenderFragment ChildContent { get; set; }

private bool _expanded;

protected override void OnInitialized()
{
_expanded = Expanded;
}

private void Toggle()
{
_expanded = !_expanded;
}
}
```

## Partial class support

Razor components are generated as partial classes. Razor components are authored using either of the following approaches:
Expand Down
4 changes: 2 additions & 2 deletions aspnetcore/blazor/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Learn how to use Razor component lifecycle methods in ASP.NET Core
monikerRange: '>= aspnetcore-3.1'
ms.author: riande
ms.custom: mvc
ms.date: 03/17/2020
ms.date: 04/16/2020
no-loc: [Blazor, SignalR]
uid: blazor/lifecycle
---
Expand Down Expand Up @@ -205,7 +205,7 @@ For information on handling errors during lifecycle method execution, see <xref:

## Stateful reconnection after prerendering

In a Blazor Server app when `RenderMode` is `ServerPrerendered`, the component is initially rendered statically as part of the page. Once the browser establishes a connection back to the server, the component is rendered *again*, and the component is now interactive. If the [OnInitialized{Async}](xref:blazor/lifecycle#component-initialization-methods) lifecycle method for initializing the component is present, the method is executed *twice*:
In a Blazor Server app when `RenderMode` is `ServerPrerendered`, the component is initially rendered statically as part of the page. Once the browser establishes a connection back to the server, the component is rendered *again*, and the component is now interactive. If the [OnInitialized{Async}](#component-initialization-methods) lifecycle method for initializing the component is present, the method is executed *twice*:

* When the component is prerendered statically.
* After the server connection has been established.
Expand Down