Fermer

janvier 24, 2024

Paramètres des composants et gestion de l’état

Paramètres des composants et gestion de l’état


La transmission de données du composant parent au composant enfant est un mécanisme de base dans une architecture orientée composants. Dans Blazor, il existe plusieurs façons dont les composants parents et enfants communiquent entre eux.

Blazor utilise un architecture orientée composants. Une application Blazor comprend plusieurs composants Blazor, petits et grands, formant un arborescence des composants.

Le rendu s’effectue de haut en bas. Les composants parents s’affichent avant les composants enfants.

Jusqu’ici, tout va bien. Mais comment transmettre les données d’un composant parent à ses enfants ? Et qu’en est-il si nous voulons transmettre des données d’un composant enfant à son parent ?

Tu peux accéder au code utilisé dans cet exemple sur GitHub.

Transmission de données du composant parent au composant enfant

Nous prendrons comme exemple une voiture et son moteur. Disons que le moteur a un mode avec trois valeurs possibles. Les valeurs sont éco, croisière et sport.

Dans la voiture, en réalité, le conducteur décide quel mode utiliser. Dans notre exemple, le Car Le composant fournit les informations en tant que paramètre au Engine composant.

Le code ressemble à ceci :

Rasoir de voiture :

<h2>Car</h2>
<Engine Mode="EngineMode.Sport" />

Moteur.rasoir :

<h3>Engine</h3>
Mode: @Mode

@code {
    [Parameter]
    public EngineMode Mode { get; set; }
}

EngineMode.cs :

public enum EngineMode
{
    Eco,
    Cruise,
    Sport
}

Nous utilisons le Parameter attribut sur le Mode propriété au sein de Engine composant. Cela indique à Blazor que nous acceptons un EngineMode à partir de n’importe quel composant utilisant le Engine composant.

Dans le composant parent, le Car composant, nous utilisons le Engine composant et fournir le mode sport comme argument pour le Enginec’est Mode propriété.

Si nous ne fournissons pas explicitement d’argument au Mode propriété au sein de Car composant, la valeur par défaut de la variable sera utilisée. Dans notre cas, nous utilisons un enum type, ce qui signifie que le premier élément de l’énumération sera utilisé.

Il faut aussi ajouter le Car composant à la Index composant. C’est la page par défaut qui se charge lorsque nous démarrons l’application.

Index.rasoir :

@page "https://www.telerik.com/"
<PageTitle>Blazor Parameters And State Management</PageTitle>
<Car />

À partir de .NET 6, nous pouvons ajouter le EditorRequired attribut pour marquer les paramètres du composant Blazor comme requis.

Moteur.rasoir :

<h3>Engine</h3>
Mode: @Mode

@code {
    [Parameter, EditorRequired]
    public EngineMode Mode { get; set; }
}

Si nous ne fournissons toujours pas de valeur lors de l’utilisation du Engine composant, nous recevons l’avertissement suivant du compilateur :

RZ2012 : le composant ‘Engine’ attend une valeur pour le paramètre ‘Mode’, mais il se peut qu’aucune valeur n’ait été fournie.

Indice: Si vous le souhaitez, vous pouvez configurer votre IDE pour qu’il traite cet avertissement comme une erreur afin d’empêcher la compilation de l’application.

Le Parameter L’attribut est simple et permet un flux de données unidirectionnel parent-enfant.

Paramètres en cascade (paramètres contextuels)

La transmission de données du parent à l’enfant est simple et fonctionne très bien. Mais que se passe-t-il si vous souhaitez fournir une valeur à plusieurs composants imbriqués ?

Oui, vous pouvez les transmettre du parent à ses enfants et encore un niveau plus bas jusqu’à ce que vous arriviez à destination. Cependant, ce n’est ni amusant ni maintenable.

C’est là que paramètres en cascade entrer en jeu. je préfère les appeler paramètres contextuels. Laissez-moi vous expliquer pourquoi et comment ils fonctionnent.

Améliorons notre exemple de code. Disons que nous ajoutons plus de détails et implémentons un FuelPump composante comme troisième niveau. Ce sera un enfant du Engine composant. Sans entrer dans les détails, la pompe à carburant d’une voiture doit également savoir quel mode moteur la voiture est censée utiliser.

La mise en œuvre du FuelPump le composant ressemble à ceci :

FuelPump.rasoir :

<h3>FuelPump</h3>
Running in mode @Mode

@code {
    [CascadingParameter]
    public EngineMode Mode { get; set; }
}

Remarquez le CascadingParameter attribut au-dessus du Mode propriété dans la section code du FuelPump composant.

Nous ajoutons le FuelPump composant à la Engine composant, ce qui donne le code suivant.

Moteur.rasoir :

<h3>Engine</h3>
Mode: @Mode

<FuelPump />

@code {
    [CascadingParameter]
    public EngineMode Mode { get; set; }
}

Nous mettons également à jour le Mode propriété dans le Engine composant pour utiliser le CascadingParameter attribut au lieu de l’attribut Parameter attribut.

Voyons maintenant comment rendre la valeur disponible dans les composants enfants du Car composant.

Rasoir de voiture :

<h2>Car</h2>

<CascadingValue Value="EngineMode.Sport">
    <Engine />
</CascadingValue>

Nous avons supprimé le EngineMode du Engine composant. Au lieu de cela, nous emballons le Engine utilisation des composants dans un CascadingValue composant. Il contient un Value propriété où nous fournissons le mode moteur.

Le CascadingValue Le composant rend une valeur disponible à tous les composants à l’intérieur de l’arborescence des composants qu’il contient.

Une arborescence de composants Blazor avec un composant Car référençant un composant CascadingValue comme son enfant.  Le composant CascadingValue fait référence à un composant Engine en tant qu'enfant.  Le composant Engine fait référence à un composant FuelPump comme son enfant.

Note: Un petit-enfant du composant parent peut consommer une valeur en cascade sans que les enfants directs ne la consomment.

Mais comment ça fonctionne?

Il utilise le type pour déterminer quelle valeur est résolue lorsqu’une propriété est décorée avec le CascadingParameter attribut.

De plus, comme pour les paramètres réguliers, chaque fois que la valeur du CascadingValue les composants changent, les enfants sont avertis et leurs valeurs sont mises à jour.

Dans l’exemple ci-dessus, nous utilisons une valeur constante. Cependant, vous pouvez également lier cette valeur à partir d’une propriété du Car composant.

Mais que se passe-t-il si nous avons plusieurs paramètres du même type ?

Si nous avons plusieurs paramètres en cascade du même type, nous pouvons nom eux. Nous pouvons fournir le Name comme deuxième propriété du CascadingValue composant lors de la définition de la valeur.

Nous pouvons également fournir un Name propriété à la CascadingParameter attribut lors de sa résolution dans les composants enfants.

Fournir des services à l’État

Bien que cet article fasse partie d’un Série Blazor, je ne me limiterai pas à parler des fonctionnalités de Blazor. Les applications Blazor sont des applications .NET et bénéficient donc de toute la puissance et des opportunités de toute autre application .NET.

En matière de gestion d’état, nous pouvons implémenter des services pour partager des données avec différents composants. Nous utilisons le @inject directive dans les composants Blazor pour accéder à une instance d’un service via injection de dépendance.

Nous pouvons ensuite appeler des méthodes sur ce service pour mettre à jour ou en recevoir des données et utiliser les données dans le composant Blazor.

Accès aux données à partir d’un composant enfant

Nous avons appris trois façons de transmettre des données d’un composant parent à ses enfants. Mais que se passe-t-il si nous voulons également accéder aux données d’un composant enfant au sein de son parent ?

Nous avons appris liaison de données dans un article précédent de ce Les bases du Blazor série. UN liaison bidirectionnelle nous aidera à lier une propriété d’un composant enfant à un composant parent.

Ajoutons un Temperature propriété à la Engine composant.

[Parameter]
public int Temperature { get; set; }

Ensuite, nous ajoutons également un EventCallback au composant. Assurez-vous de suivre la convention de dénomination : nommez la propriété de la même manière que la propriété value et ajoutez Changed à la fin.

[Parameter]
public EventCallback<int> TemperatureChanged { get; set; }

Nous modifions également le modèle du composant pour afficher la température du moteur sur l’écran.

<h3>Engine</h3>
<ul>
    <li>Mode: @Mode</li>
    <li>Temperature: @Temperature <button @onclick="ChangeTemperature">Change</button></li>
</ul>

<FuelPump />

Outre le mode, nous affichons également la température actuelle du moteur. Nous avons également un bouton à côté. Lorsque l’utilisateur appuie sur le bouton, nous souhaitons modifier la température du moteur.

Nous ajoutons ce qui suit ChangeTemperature méthode gérant le clic du bouton dans la section code du composant :

public async Task ChangeTemperature()
{
    var random = new Random();
    Temperature = random.Next(60, 400);
    await TemperatureChanged.InvokeAsync(Temperature);
}

Nous utilisons un méthode asynchrone et renvoie un Task. Nous utilisons le Random objet pour générer une nouvelle valeur pour le Temperature entre 60 et 400 degrés Celsius.

A la fin de la méthode, nous de manière asynchrone invoquer le TemperatureChanged événement. Il informera le composant parent que la valeur du Temperature la propriété a changé.

Le terminé Engine le composant ressemble à ceci :

<h3>Engine</h3>
<ul>
    <li>Mode: @Mode</li>
    <li>Temperature: @Temperature <button @onclick="ChangeTemperature">Change</button></li>
</ul>

<FuelPump />

@code {
    [CascadingParameter]
    public EngineMode Mode { get; set; }

    [Parameter]
    public int Temperature { get; set; }

    [Parameter]
    public EventCallback<int> TemperatureChanged { get; set; }

    public async Task ChangeTemperature()
    {
        var random = new Random();
        Temperature = random.Next(60, 400);
        await TemperatureChanged.InvokeAsync(Temperature);
    }
}

Ensuite, nous devons apporter quelques modifications au Car composant.

Tout d’abord, nous ajoutons un @code section, définissez une propriété de type intet nommez-le EngineTemp. Nous pouvons utiliser le nom que nous voulons. Il n’est pas nécessaire qu’il s’agisse du même nom que celui du composant enfant. Nous attribuons une valeur par défaut de 16 degrés.

@code {
    public int EngineTemp { get; set; } = 16;
}

Maintenant, nous mettons à jour le Car modèle du composant.

<h2>Car</h2>
<p>Engine Temperature: @EngineTemp</p>

<CascadingValue Value="EngineMode.Sport">
    <Engine @bind-Temperature="EngineTemp" />
</CascadingValue>

Nous utilisons le @bind-Temperature syntaxe pour lier le EngineTemp propriété du Car composant à la Temperature propriété du Engine composant.

La syntaxe @bind-[PropertyName] en fait un liaison bidirectionnelle. Comparez-le au Value propriété du CascadingValue composant. Sans le @bind devant le nom de la propriété (Valeur), il crée un liaison unidirectionnelle.

Lorsque nous démarrons l’application, nous voyons la température du moteur dans le Car composant et le Engine composant. Pour les deux composants, la valeur par défaut définie dans le Engine Le composant (16) est représenté.

Une application Web Blazor montrant un composant de voiture avec une température moteur de 16, un composant moteur avec un mode sport et une température de 16. Il y a un bouton de changement à côté de la température.  Un composant FuelPump affichant le mode sport.

Quand on appuie sur le Changement bouton sur le Engine composant, la température du moteur change. Non seulement cela change dans le Engine composant, mais également dans le composant parent (le Car composant.

Une application Web Blazor montrant un composant de voiture avec une température moteur de 248, un composant moteur avec un mode sport et une température de 248. Il y a un bouton de changement à côté de la température.  Un composant FuelPump affichant le mode sport.

Il se passe beaucoup de choses dans les coulisses. Mais pour nous, développeurs, il est assez simple de lier une valeur d’un composant parent à un composant enfant et d’être averti chaque fois que la valeur change.

Note: Ce mécanisme combine liaisons bidirectionnelles avec rappels d’événements.

Gestion centralisée de l’État

Nous avons beaucoup appris sur la transmission de données des composants parent aux composants enfants. Nous avons découvert différentes options pour le transmettre directement dans l’arbre, et nous avons découvert paramètres en cascade qui permettent d’accéder à une valeur depuis n’importe où dans l’arborescence des composants.

Cependant, il existe également une approche complètement différente.

En JavaScript, gestion centralisée de l’État C’est très populaire. Par exemple, Redux est une bibliothèque largement adoptée lors de la construction Basé sur la réaction des applications Web.

Pour Blazerquelques options de gestion centralisée de l’état sont disponibles :

Il pourrait y avoir encore plus de projets open source, moins connus, offrant une gestion centralisée de l’État.

L’objectif de cet article est de montrer les différentes options dont nous disposons pour gérer l’état et fournir des données d’un composant à un autre.

Nous ne discuterons pas ici de la gestion centralisée de l’État, mais l’objectif était de montrer toutes les options dont nous disposons. Les développeurs issus des frameworks Web JavaScript seront très probablement familiers avec le concept.

Note: Je ne l’utiliserais que lorsque vous vous serez renseigné sur les avantages et les inconvénients de l’approche étatique centralisée. De plus, ne l’implémentez pas vous-même : utilisez l’une des options disponibles.

Conclusion

Il existe différentes approches de la gestion de l’état et de la transmission des données du parent à l’enfant ou vice versa.

Les attributs Parameter et CascadingParameter fournissent une API simple pour recevoir les paramètres des composants parents.

L’approche basée sur les services utilise les fonctionnalités .NET standard pour partager des données entre différents composants à l’aide de l’injection de dépendances.

Les paramètres de liaison nous permettent d’accéder aux données des composants enfants au sein des composants parents.

Si vous souhaitez utiliser la gestion centralisée de l’état, les projets open source fournissent des implémentations pour les applications Blazor.

Tu peux accéder au code utilisé dans cet exemple sur GitHub.

Si vous souhaitez en savoir plus sur le développement de Blazor, vous pouvez regarder mon cours intensif Blazor gratuit sur YouTube. Et restez à l’écoute du blog Telerik pour en savoir plus Les bases du Blazor.




Source link