Skip to content

Commit c9d1208

Browse files
Merge pull request #17948 from dotnet/master
merge to live 21 April
2 parents f976dce + 7410ba1 commit c9d1208

18 files changed

Lines changed: 306 additions & 267 deletions

File tree

aspnetcore/blazor/components.md

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ description: Learn how to create and use Razor components, including how to bind
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 03/25/2020
8+
ms.date: 04/21/2020
99
no-loc: [Blazor, SignalR]
1010
uid: blazor/components
1111
---
1212
# Create and use ASP.NET Core Razor components
1313

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

1616
[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))
1717

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

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

137+
> [!WARNING]
138+
> 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.
139+
137140
## Child content
138141

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

393396
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.
394397

395-
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:
398+
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:
396399

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

447450
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.
448451

452+
## Don't create components that write to their own parameter properties
453+
454+
Parameters are overwritten under the following conditions:
455+
456+
* A child component's content is rendered with a `RenderFragment`.
457+
* <xref:Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged%2A> is called in the parent component.
458+
459+
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.
460+
461+
Consider the following `Expander` component that:
462+
463+
* Renders child content.
464+
* Toggles showing child content with a component parameter.
465+
466+
```razor
467+
<div @onclick="@Toggle">
468+
Toggle (Expanded = @Expanded)
469+
470+
@if (Expanded)
471+
{
472+
@ChildContent
473+
}
474+
</div>
475+
476+
@code {
477+
[Parameter]
478+
public bool Expanded { get; set; }
479+
480+
[Parameter]
481+
public RenderFragment ChildContent { get; set; }
482+
483+
private void Toggle()
484+
{
485+
Expanded = !Expanded;
486+
}
487+
}
488+
```
489+
490+
The `Expander` component is added to a parent component that may call `StateHasChanged`:
491+
492+
```razor
493+
<Expander Expanded="true">
494+
<h1>Hello, world!</h1>
495+
</Expander>
496+
497+
<Expander Expanded="true" />
498+
499+
<button @onclick="@(() => StateHasChanged())">
500+
Call StateHasChanged
501+
</button>
502+
```
503+
504+
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.
505+
506+
To maintain state in the preceding scenario, use a *private field* in the `Expander` component to maintain its toggled state.
507+
508+
The following `Expander` component:
509+
510+
* Accepts the `Expanded` component parameter value from the parent.
511+
* Assigns the component parameter value to a *private field* (`_expanded`) in the [OnInitialized event](xref:blazor/lifecycle#component-initialization-methods).
512+
* Uses the private field to maintain its internal toggle state.
513+
514+
```razor
515+
<div @onclick="@Toggle">
516+
Toggle (Expanded = @_expanded)
517+
518+
@if (_expanded)
519+
{
520+
@ChildContent
521+
}
522+
</div>
523+
524+
@code {
525+
[Parameter]
526+
public bool Expanded { get; set; }
527+
528+
[Parameter]
529+
public RenderFragment ChildContent { get; set; }
530+
531+
private bool _expanded;
532+
533+
protected override void OnInitialized()
534+
{
535+
_expanded = Expanded;
536+
}
537+
538+
private void Toggle()
539+
{
540+
_expanded = !_expanded;
541+
}
542+
}
543+
```
544+
449545
## Partial class support
450546

451547
Razor components are generated as partial classes. Razor components are authored using either of the following approaches:

aspnetcore/blazor/hosting-model-configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ Configuration files are cached for offline use. With [Progressive Web Applicatio
127127

128128
For more information on how background updates are handled by PWAs, see <xref:blazor/progressive-web-app#background-updates>.
129129

130+
### Logging
131+
132+
For information on Blazor WebAssembly logging support, see <xref:fundamentals/logging/index#create-logs-in-blazor-webassembly>.
133+
130134
## Blazor Server
131135

132136
### Reflect the connection state in the UI

aspnetcore/blazor/lifecycle.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to use Razor component lifecycle methods in ASP.NET Core
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 03/17/2020
8+
ms.date: 04/16/2020
99
no-loc: [Blazor, SignalR]
1010
uid: blazor/lifecycle
1111
---
@@ -205,7 +205,7 @@ For information on handling errors during lifecycle method execution, see <xref:
205205

206206
## Stateful reconnection after prerendering
207207

208-
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*:
208+
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*:
209209

210210
* When the component is prerendered statically.
211211
* After the server connection has been established.

aspnetcore/fundamentals/logging/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,23 @@ If you need to configure a service that depends on `ILogger<T>`, you can still d
159159

160160
The preceding highlighted code is a `Func` that runs the first time the DI container needs to construct an instance of `MyService`. You can access any of the registered services in this way.
161161

162+
### Create logs in Blazor WebAssembly
163+
164+
Configure logging in Blazor WebAssembly apps with the `WebAssemblyHostBuilder.Logging` property in `Program.Main`:
165+
166+
```csharp
167+
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
168+
169+
...
170+
171+
var builder = WebAssemblyHostBuilder.CreateDefault(args);
172+
173+
builder.Logging.SetMinimumLevel(LogLevel.Debug);
174+
builder.Logging.AddProvider(new CustomLoggingProvider());
175+
```
176+
177+
The `Logging` property is of type <xref:Microsoft.Extensions.Logging.ILoggingBuilder>, so all of the extension methods available on <xref:Microsoft.Extensions.Logging.ILoggingBuilder> are also available on `Logging`.
178+
162179
### No asynchronous logger methods
163180

164181
Logging should be so fast that it isn't worth the performance cost of asynchronous code. If your logging data store is slow, don't write to it directly. Consider writing the log messages to a fast store initially, then move them to the slow store later. For example, if you're logging to SQL Server, you don't want to do that directly in a `Log` method, since the `Log` methods are synchronous. Instead, synchronously add log messages to an in-memory queue and have a background worker pull the messages out of the queue to do the asynchronous work of pushing data to SQL Server. For more information, see [this](https://github.com/dotnet/AspNetCore.Docs/issues/11801) GitHub issue.

0 commit comments

Comments
 (0)