Regardez un ajout expérimental à l’API du signal – likedSignal (). Il aide les développeurs à gérer les états dépendants.
L’État fait référence aux données qui alimentent les applications. Une caractéristique des données avec état est la réactivité, ce qui signifie que chaque fois que l’état d’application change, il doit être immédiatement reflété dans l’interface utilisateur. Dans les applications angulaires, l’état est géré à l’aide de trois primitives réactives: variables d’instance régulières, observables ou signaux. De toutes ces primitives, les signaux sont le dernier ajout.
Les signaux existaient déjà dans d’autres cadres, mais ont été officiellement introduits dans Angular dans la version 17. Les signaux facilitent les développeurs incroyablement faciles de gérer les tâches de gestion des états simples et complexes en utilisant leur API synchrone facile à utiliser.
Dans ce guide, nous examinerons un ajout expérimental à l’API Signal –linkedSignal()
Cela aide les développeurs à gérer l’état dépendant, ce qui était difficile à faire avec l’API existant. Nous montrerons des utilisations simples et plus avancées de cette fonction.
Traiter avec les États dépendants a de nombreux cas d’utilisation du monde réel qui partagent tous la même idée centrale. Dans notre cas, notre mini application sera une forme simple axée sur un modèle avec des champs d’entrée dépendants. Commençons.
Condition préalable
Pour procéder à ce guide, il est supposé que vous connaissez TypeScript de base et un cadre frontal.
Configuration du projet
En supposant que vous avez le CLI angulaire Installé, ouvrez votre terminal et exécutez la commande suivante dans le dossier souhaité pour créer un projet angulaire.
ng new linked-signals-intro
Dans notre cas, notre projet est logé dans un dossier appelé lien-signal-intro. Suivez l’invite pour configurer votre application angulaire et installer les dépendances nécessaires.
Préambule de l’API du signal
Maintenant, discutons brièvement des fonctions déjà existantes fournies par l’API Signal. Cela nous permettra de comprendre comment fonctionne l’API du signal et comment les signaux liés s’accumulent au-dessus.
Avant le linkedSignal()
Une fonction a été ajoutée, l’ancienne API était composée de trois fonctions principales: signal()
, computed()
et effect()
.
Signal
Le signal()
La fonction est la base de toutes les autres fonctions fournies par l’API. Comme vous l’avez peut-être déjà deviné, cette fonction est utilisée pour créer un signal.
Voici une utilisation simple de cette fonction:
user = signal({ fullName: "John Doe", id: 1, phoneNumber: "" });
L’appel au signal()
La fonction attend un objet primitif ou. Dans notre cas, l’appel renvoie un emballage autour du user
objet. Signaux créés à l’aide du signal()
La fonction est les deux lisible et scrutin.
Par exemple, pour lire le id
de l’objet utilisateur, nous pouvons le faire:
user().id.
Et pour écrire au signal, nous pouvons utiliser le set()
ou update()
Méthodes.
user.set({ fullName: "John Doe", id: 1, phoneNumber: "1234" });
user.update((prevUser) => ({ ...prevUser, phoneNumber: "56789" }));
Effet
Le effect()
La fonction accepte un rappel qui s’exécute de manière asynchrone à chaque fois que les signaux utilisés dans le changement de rappel. Par exemple, nous pouvons écrire du code pour appeler une API tierce ou imprimer quelques journaux pour le débogage.
authStatus = signal("authenticated");
effect(() => {
console.log("the user is now " + authStatus());
});
Dans l’exemple ci-dessus, nous écrivons un effet qui imprime un message à l’écran chaque fois que l’état d’authentification change.
Calculé
Cette fonction nous permet de dériver un signal d’un autre signal. Il reçoit une fonction de rappel qui calcule une valeur basée sur un ou plusieurs signaux. Le rappel est recalculé chaque fois que l’un des signaux utilisés dans le corps du rappel change.
firstname = signal("john");
lastname = signal("bobo");
fullname = computed(() => firstname() + " " + lastname());
Dans l’exemple ci-dessus, nous créons un signal calculé appelé fullname
qui concaténe simplement les valeurs du firstname
et lastname
signaux.
Il est important de noter qu’une tentative de modification de la valeur d’un signal dans le rappel a passé à
effect()
oucomputed()
est un antipatdern et peut facilement introduire des bogues dans les applications.
Le principal problème avec les signaux calculés est que, bien qu’ils nous aident à créer des relations entre l’état en nous permettant de dériver de nouveaux signaux à partir d’un ou plusieurs signaux, les signaux résultants qu’ils produisent ne sont pas écrivains. Dans notre cas, fullname
n’est pas scédé à l’écriture; Il est en lecture seule.
LinkedSignal
Les signaux liés sont assez similaires aux signaux générés en utilisant le computed()
Fonctionne en ce qu’ils nous permettent de créer des relations entre les signaux en nous permettant de calculer de nouveaux signaux à partir d’une ou plusieurs sources.
Les différences entre les signaux créés avec le computed()
fonction et celles créées en utilisant le linkedSignal()
La fonction est la suivante:
Notez que le
linkedSignal()
La fonction a deux variantes surchargées comme nous le verrons ensuite.
- Le
linkedSignal()
La fonction permet la création de signaux calculés en écriture, ce qui rend son comportement identique à l’utilisation uniquement de la plainesignal()
fonction. Signaux créés à partir ducomputed()
La fonction est en lecture seule.
@Component({
selector: 'dummy-comp',
template: `<button (click)="this.update()">update</button>`,
})
export class DummyComponent {
value = signal(3);
valueSquare = linkedSignal(() => this.value() \* this.value());
dummyUpdate() {
this.value.set(9);
this.value.set(5);
this.valueSquare.set(121);
}
}
Dans l’exemple ci-dessus, valueSquare
tire sa valeur du carré du value
signal. Chaque fois que nous mettons à jour le value
signal, valueSquare
est recalculé. Aussi, depuis valueSquare
est juste un signal régulier, nous pouvons le mettre à jour directement en utilisant son set()
ou update()
Méthodes.
- Un avantage supplémentaire des signaux liés est qu’ils fournissent plus de contrôle lors de la création du signal calculé. Ils permettent aux développeurs d’utiliser les valeurs précédentes du signal calculé et les sources utilisées pour les générer pour aider à déterminer la nouvelle valeur du signal.
@Component({
selector: "dummy-comp",
template: `<button (click)="this.update()">update</button>`,
})
export class DummyComponent1 {
value = signal(10);
evenValue = linkedSignal({
source: () => this.value(),
computation(currentSource, old) {
if (currentSource % 2 === 0) {
return currentSource;
}
return old?.value % 2 === 0 ? old?.value : 0;
},
});
update() {
this.value.set(13);
this.value.set(14);
evenValue.set(64);
}
}
Dans l’extrait de code ci-dessus, evenValue
dépend de value
; Cependant, il utilise la définition plus verbeuse du linkedSignal()
fonction qui accepte deux paramètres obligatoires. Le premier paramètre, source
est un rappel qui se résout à un ou plusieurs signaux evenValue
sera dérivé de. Vous pouvez retourner un objet au cas où vous souhaitez utiliser plusieurs signaux. Dans notre cas, il n’a renvoyé que le signal de valeur.
Le deuxième paramètre est computed
qui est un rappel destiné à renvoyer une valeur réelle pour evenValue
. Il accepte deux paramètres: la valeur actuelle de la source (s) et un deuxième paramètre qui est un objet qui contient la valeur précédente de evenValue
et les signaux source (s) utilisés pour le calculer.
evenValue
peut être modifié directement en utilisant son set()
ou update()
Des méthodes comme un signal régulier, ou si le signal de valeur, il dépend de un nombre pair. Cependant, si le signal de valeur contient un nombre impaire, il essaiera de vérifier si la valeur précédente de value
(c’est-à-dire, old?.value
) est même, puis il résout cette valeur; sinon il se résout à 0.
Ce que nous allons construire
Nous avons déjà établi le fonctionnement des signaux liés et des différentes façons d’invoquer le linkedSignal
fonction dans les composants.
Dans cette section, nous montrerons un cas d’utilisation pratique dans une application simple. Nous allons construire un formulaire d’admission simple qui permet à l’utilisateur de choisir une université, puis de sélectionner la majeure souhaitée.
Le but de notre application est à nouveau de montrer comment les signaux liés nous aident à travailler avec un état dépendant et à montrer les différentes formes d’utilisation de la surcharge linkedSignal()
fonction.
Tout le code que nous écrivons ira dans notre app.component.ts
déposer.
Pour l’instant, ce fichier ressemble à ceci:
import { Component, computed, signal, linkedSignal } from "@angular/core";
import { FormsModule } from "@angular/forms";
@Component({
selector: "app-root",
template: ``,
imports: [FormsModule],
})
export class AppComponent {}
Pour les importations, nous avons inclus la plupart des fonctions incluses dans l’API Signal. Ensuite, nous avons importé le FormModule
ce qui nous aidera lors de la création de nos formulaires. Nous sommes seulement intéressés à utiliser le ngModel
directive sous notre forme.
Notre application contiendra quatre signaux. Mettons maintenant à jour progressivement le app.component.ts
fichier pour ressembler à ceci:
type Tmajor = {
id: string;
name: string;
};
type Tinstitution = {
id: string;
name: string;
majors: Tmajor[];
};
const INSTITUTIONS: Tinstitution[] = [
{
id: "1",
name: "univerity 1",
majors: [
{
id: "1",
name: "computer Science",
},
{
id: "2",
name: "Engineering",
},
{
id: "3",
name: "Psycology",
},
],
},
{
id: "2",
name: "univerity 2",
majors: [
{
id: "4",
name: "Arts",
},
{
id: "1",
name: "computer Science",
},
],
},
];
@Component({
selector: "app-root",
template: `
<section class="prose lg:prose-xl mx-auto pt-10">
<div
class="rounded-sm max-w-[400px] mx-auto border border-neutral-600 p-7"
>
<div class="grid gap-3">
<div class="text-center ">
<h3>Admission form</h3>
</div>
<label class="form-control w-full grid">
<div class="label">
<span class="label-text">Pick university</span>
</div>
<select
class="select select-bordered"
[(ngModel)]="selectedInstitution"
>
@for (major of institutions(); track $index) {
<option [value]="major.id">{{ major.name }}</option>
}
</select>
</label>
</div>
</div>
</section>
`,
imports: [FormsModule],
})
export class AppComponent {
institutions = signal(INSTITUTIONS);
selectedInstitution = linkedSignal(() => this.institutions()[0].id);
}
Nous avons créé une liste d’institutions codées en dur et leurs majors dans une variable appelée INSTITUTIONS
. Notez qu’une majeure peut être offerte. Ensuite, dans le app
Composant, nous enroulons cet objet dans un signal appelé institution
et nous le rendons dans l’interface utilisateur dans un select
dérouler.
Nous avons configuré un signal lié appelé selectedInstitution
Parce que, par défaut, nous voulons que la première institution soit sélectionnée, et nous voulons également permettre à l’utilisateur de mettre à jour son choix en choisissant une institution dans la liste déroulante.
@Component({
selector: "app-root",
template: `
<section class="prose lg:prose-xl mx-auto pt-10">
<div
class="rounded-sm max-w-[400px] mx-auto border border-neutral-600 p-7"
>
<div class="grid gap-3">
<div class="text-center ">
<h3>Admission form</h3>
</div>
<label class="form-control w-full grid"> //...form field </label>
//Add this
<label class="form-control w-full grid">
<div class="label">
<span class="label-text">Pick your major</span>
</div>
<select class="select select-bordered" [(ngModel)]="major">
@for (major of majors(); track $index) {
<option [value]="major.id">{{ major.name }}</option>
}
</select>
</label>
</div>
</div>
</section>
`,
imports: [FormsModule],
})
export class AppComponent {
institutions = signal(INSTITUTIONS);
selectedInstitution = linkedSignal(() => this.institutions()[0].id);
majors = computed(() => {
const chosenInstitution = this.institutions().find(
(ins) => ins.id === this.selectedInstitution()
);
if (chosenInstitution) {
return chosenInstitution.majors;
}
return [];
});
major = linkedSignal<Tmajor[], string>({
source: this.majors,
computation(currentSource, oldData) {
const existingMajor = currentSource.find(
(maj) => maj.id === oldData?.value
);
if (existingMajor) {
return existingMajor.id;
}
return currentSource[0].id;
},
});
}
Dans le code ci-dessus, nous maintenons un signal appelé majors
Cela dépend du selectedInstitution
signal. Comme nous n’avons pas l’intention de modifier sa valeur, nous avons résolu sa valeur en utilisant le computed()
fonction car il génère des signaux en lecture. La liste des majors à nouveau est rendue dans un select
dérouler.
Le major
Le signal dépend à nouveau de la liste des majors et doit être écrivable car il est lié au select
Dropdown, il est donc emballé comme un signal lié. Nous avons choisi la définition plus verbeuse pour pouvoir résoudre la valeur correcte.
Dans le computation
Fonction, nous définissons la valeur par défaut sur la première majeure sélectionnée parmi l’institution actuelle.
Votre application devrait ressembler à ceci:
Cependant, si le institution
est modifié et le majors
La liste des modifications, et la majeure précédemment sélectionnée apparaît dans la nouvelle liste des majors, elle n’est pas modifiée.
Conclusion
Les signaux ne sont pas censés être un remplacement des observables ou d’autres primitives réactives soutenues par Angular. Ils fournissent simplement une alternative qui fait le travail et est facile à utiliser et à comprendre par les développeurs. Ce guide comprend des informations sur un ajout à cette API qui peuvent être utilisées pour résoudre la façon dont nous gérons l’état dépendant dans nos projets angulaires.
En savoir plus sur Signaux en angulaire.
Source link