Pierwsze kroki z Angular Signals

1. Zanim zaczniesz

czarne logo Angular

Angular Signals wprowadza 3 reaktywne prymitywy do znanej i lubionej przez Ciebie wersji Angular, które upraszczają proces tworzenia aplikacji i ułatwiają szybsze tworzenie aplikacji.

Co utworzysz

  • Poznasz 3 reaktywne prymitywy wprowadzone w Angular Signals: signal(), computed()effect().
  • Używanie sygnałów Angular do obsługi gry Angular Cipher. Mechanizmy szyfrowania to systemy służące do szyfrowania i odszyfrowywania danych. W tej grze użytkownicy mogą odkodować tajną wiadomość, przeciągając i upuszczając wskazówki, aby rozwiązać szyfr, dostosować wiadomość i udostępnić adres URL, aby wysłać tajne wiadomości do znajomych.

Gra ukośna w stylu starej zielonej konsoli do gier, z ukrytą wiadomością na ekranie: „Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!”.

Wymagania wstępne

2. Pobierz kod

Wszystko, czego potrzebujesz do tego projektu, znajdziesz w Stackblitz. Do pracy w tym ćwiczeniu zalecamy metodę Stackblitz. Możesz też skopiować kod i otworzyć go w swoim ulubionym środowisku programistycznym.

Otwórz Stackblitz i uruchom aplikację.

Aby rozpocząć, otwórz link Stackblitz w ulubionej przeglądarce:

  1. Otwórz nową kartę przeglądarki i wejdź na https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcipher%2Fservice.cipher.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts
  2. Utwórz rozwidlenie w usłudze Stackblitz, aby utworzyć własny obszar roboczy z możliwością edytowania. Stackblitz powinien automatycznie uruchomić aplikację.

Alternatywna metoda: klonowanie repozytorium i usługa aplikacji

Alternatywą dla tego ćwiczenia jest użycie VS Code lub lokalnego IDE:

  1. Otwórz nową kartę przeglądarki i wejdź na stronę https://github.com/angular/codelabs/tree/signals-get-started.
  2. Wykonaj fork repozytorium i sklonuj je, a następnie użyj polecenia cd codelabs/, aby przejść do repozytorium.
  3. Sprawdź gałąź kodu startowego za pomocą polecenia git checkout signals-get-started.
  4. Otwórz kod w VSCode lub ulubionym środowisku IDE.
  5. Aby zainstalować zależności wymagane do uruchomienia serwera, użyj polecenia npm install.
  6. Aby uruchomić serwer, użyj polecenia ng serve.
  7. Otwórz kartę przeglądarki i wejdź na stronę http://localhost:4200.

3. Ustal wartość odniesienia

Punkt początkowy to gra Angular Cipher, ale jeszcze nie działa. Angular Signals będzie obsługiwać funkcje gry.

Gra w kodowanie w stylu zielonej konsoli do gier z ukrytą wiadomością na ekranie „Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!'

Na początek zapoznaj się z gotową wersją elementów, które będziesz tworzyć: Angular Signals Cypher.

  1. Zobacz kodowany komunikat na ekranie.
  2. Przeciągnij i upuść przycisk z literą na klawiaturze, aby odszyfrować i odkodować tajną wiadomość.
  3. Gdy operacja się uda, sprawdź, jak wiadomość jest aktualizowana, aby zdekodować dalszą część tajnej wiadomości.
  4. Kliknij Dostosuj, aby zmienić nadawcę i wiadomość, a następnie kliknij Utwórz i skopiuj URL, aby zobaczyć wartości na ekranie i zmienić adres URL.
  5. Bonus: skopiuj i wklej adres URL na nowej karcie lub udostępnij go znajomemu i zobacz, jak nadawca i wiadomość są przechowywane w adresie URL.

Obraz GIF przedstawiający grę Angular Cypher z ukrytą wiadomością dekodowaną na ekranie i napisem „Angular Signals są w wersji deweloperskiej dzisiaj w wersji 16!”.

4. Definiowanie pierwszego sygnału

Sygnał to wartość, która może informować Angular o zmianie. Niektóre sygnały można zmienić bezpośrednio, a inne obliczają ich wartości na podstawie wartości innych sygnałów. Połączenie tych sygnałów tworzy bezpośredni wykres zależności, który modeluje przepływ danych w aplikacji.

Angular może korzystać z powiadomień dotyczących sygnałów, aby wiedzieć, które komponenty należy wykryć zmiany, lub wykonać zdefiniowane przez Ciebie funkcje efektywne.

Zmień superSecretMessage na signal()

superSecretMessage to wartość w elementach MessageService, która określa tajną wiadomość, którą gracz ma odkodować. Obecnie wartość nie informuje aplikacji o zmianach, więc przycisk Dostosuj jest uszkodzony. Możesz rozwiązać ten problem, korzystając z usługi Signal.

Jeśli ustawisz superSecretMessage jako sygnał, możesz powiadomić niektóre elementy aplikacji, które będą otrzymywać informacje o zmianie komunikatu. Gdy dostosujesz wiadomość w dialogu, ustawisz sygnał, aby zaktualizować resztę aplikacji.

Aby określić pierwszy sygnał, w komentarzu TODO(1): Define your first signal() w każdym pliku wykonaj te czynności:

  1. W pliku service.message.ts użyj biblioteki sygnałów, aby ustawić superSecretMessage jako reaktywne:

src/app/secret-message/service.message.ts

superSecretMessage = signal(
  'Angular Signals are in developer preview in v16 today!'
);

Dzięki temu automatycznie pojawi się prośba o importowanie signal@angular/core. Jeśli odświeżysz stronę, prawdopodobnie pojawią się błędy w miejscach, w których wcześniej odwoływaliśmy się do superSecretMessage. Wynika to ze zmiany typu elementu superSecretMessagestring na SettableSignal<string>. Możesz to naprawić, zmieniając wszystkie odwołania do superSecretMessage, aby używały interfejsu Signals API. Gdziekolwiek odczytujesz wartość, wywołaj funkcję Signal getter superSecretMessage(). Wszędzie tam, gdzie wpiszesz wartość, użyj interfejsu API .set w witrynie SettableSignal, aby ustawić nową wartość dla wiadomości.

  1. W plikach secret-message.tsservice.message.ts zaktualizuj wszystkie odwołania do superSecretMessage na superSecretMessage():

src/app/secret-message/secret-message.ts

// Before
this.messages.superSecretMessage
this.messages.superSecretMessage = message;

// After
this.messages.superSecretMessage()
this.messages.superSecretMessage.set(message);

src/app/secret-message/service.message.ts

// Before
this.superSecretMessage

// After
this.superSecretMessage()

Przeanalizuj 2 pozostałe sygnały

  • Zwróć uwagę, że w Twojej aplikacji masz jeszcze 2 inne sygnały:

src/app/cipher/service.cipher.ts

cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);

CipherService definiuje sygnał cipher, losowo wygenerowane mapowanie par klucz-wartość jednej litery alfabetu na nową literę cipher. Służy on do szyfrowania wiadomości i określania, czy gracz znajdzie na klawiaturze udane dopasowanie.

Posiadasz też sygnał decodedCipher z zdekodowanymi parami klucz-wartość, który musisz dodać, gdy odtwarzacz rozwiąże szyfr.

Unikalną i potężną cechą biblioteki Signals w Angular jest to, że możesz stosować reakcje wszędzie. Sygnały są definiowane raz w usługach aplikacji i można ich używać w szablonach, komponentach, kanałach, innych usługach lub w dowolnym miejscu, w którym można pisać kod aplikacji. Nie są one ograniczone ani powiązane z zakresem komponentu.

Zweryfikuj zmiany

  • Zanim aplikacja zacznie działać, musisz wykonać jeszcze jeden krok. Na razie spróbuj dodać console.log() w różnych częściach aplikacji, aby zobaczyć, jak konfiguruje się nowy superSecretMessage.

Stackblitz z komunikatem Konsoli.log() pokazującym superSecretMessage prawidłowo zarejestrowanym nową wiadomość.

5. Definiowanie pierwszej funkcji skompilowanej

W wielu sytuacjach możesz wyprowadzić stan z dotychczasowych wartości. Lepiej jest aktualizować stan pochodny, gdy zmienia się wartość zależna.

Dzięki atrybucie computed() możesz deklaratywnie wyrazić sygnał, który czerpie swoją wartość z innych sygnałów.

Konwertowanie solvedMessage na computed()

solvedMessage przekształca wartość secretMessage z zakodowanej w zdekodowaną przy użyciu sygnału decodedCipher.

To bardzo przydatne, ponieważ widzisz, że generujesz dane obliczone na podstawie innego obliczonego wyniku, więc za każdym razem, gdy sygnał w tym zmapowanym kontekście reaktywnym zmieni się, zależności są powiadamiane.

Obecnie parametr solvedMessage nie jest aktualizowany po zmianie wartości parametrów secretMessage, decodedCipher lub superSecretMessage. Gdy gracz rozwiąże szyfr, nie zobaczysz zmian na ekranie.

Ustawienie solvedMessage jako obliczanego powoduje utworzenie kontekstu reaktywnego, dzięki czemu po zaktualizowaniu wiadomości lub rozwiązaniu szyfru możesz uzyskać stan zaktualizowany na podstawie śledzonych zależności.

Aby przekonwertować plik solvedMessage na plik computed(), w każdym pliku wykonaj te czynności w komentarzu TODO(2): Define your first computed():

  1. W pliku service.message.ts użyj biblioteki Signals, aby uczynić element solvedMessage reaktywnym:

src/app/secret-message/service.message.ts

solvedMessage = computed(() =>
  this.translateMessage(
    this.secretMessage(), 
    this.cipher.decodedCipher()
  )
);

Dzięki temu automatycznie pojawi się prośba o importowanie computed@angular/core. Jeśli odświeżysz stronę, prawdopodobnie pojawią się błędy w miejscach, w których wcześniej odwoływaliśmy się do solvedMessage. Dzieje się tak, ponieważ typ funkcji superSecretMessage został zmieniony z string na Signal<string> (funkcję). Możesz to naprawić, zmieniając wszystkie odwołania do solvedMessage na solvedMessage().

  1. W pliku secret-message.ts zaktualizuj wszystkie odwołania do solvedMessage na solvedMessage():

src/app/secret-message/secret-message.ts

// Before
<span *ngFor="let char of this.messages.solvedMessage.split(''); index as i;" [class.unsolved]="this.messages.solvedMessage[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

// After
<span *ngFor="let char of this.messages.solvedMessage().split(''); index as i;" [class.unsolved]="this.messages.solvedMessage()[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

Pamiętaj, że w przeciwieństwie do superSecretMessage, solvedMessage nie jest SettableSignal – nie możesz zmienić jego wartości bezpośrednio. Zamiast tego jego wartość jest aktualizowana za każdym razem, gdy aktualizowane są sygnały zależności (secretMessagedecodedCipher).

Poznaj 2 inne computed() funkcje

  • Zwróć uwagę, że w aplikacji masz jeszcze 2 inne wartości obliczone:

src/app/secret-message/service.message.ts

secretMessage = computed(() => 
  this.translateMessage(
    this.superSecretMessage(),
    this.cipher.cipher()
  )
);

src/app/cipher/service.cipher.ts

unsolvedAlphabet = computed(() =>
  ALPHABET.filter(
    (letter) => !this.decodedCipher().find((guess) => guess.value === letter)
  )
);

MessageService definiuje obliczoną secretMessage, superSecretMessage zakodowaną przez cipher, którą gracze muszą rozwiązać.

CipherService definiuje obliczony unsolvedAlphabet, czyli listę wszystkich liter, których gracz nie rozwiązał, która pochodzi z listy rozwiązanych kluczy szyfrujących w decodedCipher.

Zweryfikuj zmiany

Teraz, gdy superSecretMessage jest sygnałem, a solvedMessage jest obliczone, aplikacja powinna działać. Testowanie funkcji gry:

  1. Przeciągnij i upuść LetterGuessComponent do LetterKeyComponent w CipherComponent, aby odszyfrować i odkodować tajną wiadomość.
  2. Zobacz, jak SecretMessageComponent zmienia się wraz z dekodowaniem kolejnych części tajnej wiadomości.
  3. Aby zmienić wartości nadawcy i wiadomości, kliknij Dostosuj, a potem Utwórz i skopiuj adres URL.
  4. Bonus: skopiuj i wklej adres URL na nowej karcie lub udostępnij go znajomemu i zobacz, jak nadawca i wiadomość są przechowywane w adresie URL.

GIF przedstawiający grę Angular Cypher z ukrytą wiadomością, która na ekranie jest odkodowywana na hasło „Angular Signals are in developer preview in v16 today!” (Czujniki Angular są dostępne w wersji 16 w wersji dla deweloperów).

6. Dodawanie pierwszego efektu

Czasami może się zdarzyć, że chcesz, aby coś miało miejsce, gdy sygnał ma nową wartość. Za pomocą funkcji effect() możesz zaplanować i wykonywać funkcję obsługi w odpowiedzi na zmiany sygnałów.

Dodawanie konfetti po rozwiązaniu szyfru

Teraz gdy aplikacja już działa, możesz dodać konfetti, gdy szyfr zostanie rozwiązany, a tajna wiadomość zostanie odkodowana.

Aby dodać konfetti, wykonaj te czynności:TODO(3): Add your first effect()

  1. W pliku cipher.ts zaplanuj efekt, który doda konfetti po zdekodowaniu wiadomości:

src/app/cipher/cipher.ts

import * as confetti from 'canvas-confetti';

ngOnInit(): void {
  ...

  effect(() => {
    if (this.messages.superSecretMessage() === this.messages.solvedMessage()) {
      var confettiCanvas = document.getElementById('confetti-canvas');
      confetti.create()(confettiCanvas, { particleCount: 100 });
    }
  });
}

Zwróć uwagę, że ten efekt zależy od sygnału i obliczonej wartości: this.messages.superSecretMessage()this.messages.solvedMessage().

Efekt pomaga zaplanować funkcję konfetti w kontekście reaktywnym, aby śledzić i ponownie oceniać, kiedy są aktualizowane jej zależności.

Weryfikowanie zmian

  • Spróbuj odszyfrować wiadomość (wskazówka: aby test przebiegł szybciej, możesz zmienić wiadomość na krótszą). Pudełko konfetti pogratuluje Ci pierwszego effect() roku.

GIF z grą Angular Cypher, w której na ekranie dekodowana jest ukryta wiadomość „Confetti time!” (Czas na konfetti). Po rozwiązaniu wiadomości wyskakują konfetti.

7. Gratulacje!

Twój szyfr Angular jest już gotowy do dekodowania i udostępniania tajnych wiadomości. Masz wiadomość dla zespołu Angular? Oznacz nasze media społecznościowe (@Angular), abyśmy mogli je odkodować. 🎉

Rozwiązanie gry Angular Cypher z ukrytą wiadomością na ekranie „Angular Signals są dostępne w wersji 16 w wersji wstępnej dla deweloperów”.

W zestawie narzędzi Angular masz teraz 3 nowe podstawowe elementy reaktywne, które upraszczają programowanie i domyślnie tworzą szybsze aplikacje.

Więcej informacji

Zapoznaj się z tymi ćwiczeniami z programowania:

Przeczytaj te materiały: