Pierwsze kroki z Angular Signals

1. Zanim zaczniesz

czarne logo Angular,

Sygnały Angulara wprowadzają 3 reaktywne elementy pierwotne do znanego i lubianego Angulara, upraszczając proces tworzenia i pomagając domyślnie budować szybsze aplikacje.

Co utworzysz

  • Poznasz 3 reaktywne elementy pierwotne wprowadzone w Angular Signals: signal(), computed()effect().
  • Użyj sygnałów Angulara, aby stworzyć grę Angular Cipher. Szyfry to systemy szyfrowania i odszyfrowywania danych. W tej grze użytkownicy mogą dekodować tajną wiadomość, przeciągając i upuszczając wskazówki, aby rozwiązać mechanizm szyfrowania. Mogą też dostosować wiadomość i udostępnić adres URL, aby wysyłać tajne wiadomości do znajomych.

Gra Angular Cypher 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. Stackblitz to zalecana metoda pracy z tym ćwiczeniem z programowania. Możesz też sklonować kod i otworzyć go w ulubionym środowisku programistycznym.

Otwórz Stackblitz i uruchom aplikację

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

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

Alternatywa: sklonuj repozytorium i udostępnij aplikację

Korzystanie z VS Code lub lokalnego IDE to alternatywna metoda wykonywania tych ćwiczeń z programowania:

  1. Otwórz nową kartę przeglądarki i wejdź na stronę https://github.com/angular/codelabs/tree/signals-get-started.
  2. Utwórz fork i sklonuj repozytorium, 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 w ulubionym 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 z adresem http://localhost:4200.

3. Ustalenie wartości odniesienia

Punktem wyjścia jest gra Angular Cipher, ale jeszcze nie działa. Funkcje gry będą oparte na sygnałach Angulara.

Gra Angular Cypher w stylu starej 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ą tego, co będziesz tworzyć: Angular Signals Cypher.

  1. Wyświetl zakodowaną wiadomość na ekranie.
  2. Przeciągnij i upuść przycisk z literą na klawiaturze, aby rozwiązać szyfr i odszyfrować tajną wiadomość.
  3. Jeśli Ci się uda, zobaczysz, jak wiadomość się zmienia, aby odszyfrować więcej jej fragmentów.
  4. Kliknij Dostosuj, aby zmienić nadawcę i wiadomość, a potem kliknij Utwórz i skopiuj URL, aby zobaczyć wartości na ekranie i zmianę adresu URL.
  5. Dodatkowo: skopiuj i wklej adres URL na nowej karcie lub udostępnij go znajomemu i sprawdź, jak nadawca i wiadomość są przechowywane w adresie URL.

GIF z gry Angular Cypher, w której na ekranie jest odszyfrowywana ukryta wiadomość: „Angular Signals are in developer preview in v16 today!” (Sygnały Angulara są dziś dostępne w wersji przedpremierowej dla deweloperów w wersji 16!).

4. Definiowanie pierwszego sygnału()

Sygnał to wartość, która może informować Angulara o zmianie. Niektóre sygnały można zmieniać bezpośrednio, a inne obliczają swoje wartości na podstawie wartości innych sygnałów. Sygnały tworzą skierowany graf zależności, który modeluje przepływ danych w aplikacji.

Angular może używać powiadomień z sygnałów, aby określać, które komponenty wymagają wykrywania zmian, lub wykonywać zdefiniowane przez Ciebie funkcje efektu.

Przekształć superSecretMessage w signal()

superSecretMessage to wartość w MessageService, która określa tajną wiadomość, jaką gracz musi odszyfrować. Obecnie wartość nie powiadamia aplikacji o zmianach, więc przycisk Dostosuj nie działa. Możesz to rozwiązać za pomocą sygnału.

Ustawiając superSecretMessage jako sygnał, możesz powiadamiać części aplikacji, które zależą od informacji o zmianie wiadomości. Gdy dostosujesz wiadomość w oknie dialogowym, ustawisz sygnał, aby zaktualizować resztę aplikacji o nową wiadomość.

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

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

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

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

Automatycznie pojawi się prośba o zaimportowanie signal@angular/core. Jeśli odświeżysz stronę, prawdopodobnie wystąpią błędy w miejscach, w których wcześniej użyto symbolu superSecretMessage. Dzieje się tak, ponieważ zmieniono typ superSecretMessagestring na SettableSignal<string>. Aby rozwiązać ten problem, zmień wszystkie odwołania do superSecretMessage, aby korzystać z interfejsu Signals API. W każdym miejscu, w którym odczytujesz wartość, wywołaj funkcję pobierającą sygnał superSecretMessage(). W miejscu, w którym wpisujesz wartość, użyj interfejsu .set API w SettableSignal, aby ustawić nową wartość 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()

Poznaj 2 pozostałe sygnały

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

src/app/cipher/service.cipher.ts

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

Znak CipherService definiuje cipher sygnał, czyli losowo wygenerowane mapowanie par klucz-wartość składających się z jednej litery alfabetu na nową cipher literę. Używasz go do zaszyfrowania wiadomości i sprawdzenia, czy gracz znajdzie odpowiednie dopasowanie na klawiaturze.

Masz też sygnał decodedCipher, który wskazuje, że pary klucz-wartość zostały prawidłowo zdekodowane. Będziesz go uzupełniać w miarę rozwiązywania szyfru przez gracza.

Unikalną i ważną cechą biblioteki sygnałów Angulara jest to, że reaktywność można wprowadzić wszędzie. Sygnały definiujesz raz w usługach aplikacji i możesz ich używać w szablonie, komponentach, potokach, innych usługach lub w dowolnym miejscu, w którym możesz pisać kod aplikacji. Nie są one ograniczone do zakresu komponentu.

Weryfikowanie zmian

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

Stackblitz z komunikatem console.log() pokazującym, że superSecretMessage prawidłowo rejestruje nowy komunikat.

5. Określanie pierwszej funkcji computed()

W wielu sytuacjach możesz wywnioskować stan na podstawie istniejących wartości. Lepiej jest aktualizować stan pochodny, gdy zmieni się wartość zależna.

Za pomocą atrybutu computed() możesz deklaratywnie wyrazić sygnał, którego wartość pochodzi z innych sygnałów.

Przekształć solvedMessage w computed()

solvedMessage tłumaczy wartość secretMessage z zakodowanej na odkodowaną za pomocą sygnału decodedCipher.

Jest to szczególnie przydatne, ponieważ możesz zobaczyć, że obliczenia są wykonywane na podstawie innych obliczeń, więc za każdym razem, gdy sygnał w mapowanym kontekście reaktywnym ulegnie zmianie, zależności są o tym powiadamiane.

Obecnie solvedMessage nie jest aktualizowany, gdy zmienisz secretMessage, decodedCipher lub superSecretMessage. Dlatego nie widzisz aktualizacji ekranu, gdy gracz rozwiązuje szyfr.

Dzięki przekształceniu solvedMessage w wartość obliczaną tworzysz kontekst reaktywny, dzięki czemu po zaktualizowaniu wiadomości lub rozwiązaniu szyfru możesz wywnioskować aktualizację stanu ze śledzonych zależności.

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

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

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

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

Automatycznie pojawi się prośba o zaimportowanie computed@angular/core. Jeśli odświeżysz stronę, prawdopodobnie wystąpią błędy w miejscach, w których wcześniej użyto symbolu solvedMessage. Dzieje się tak, ponieważ typ superSecretMessage został zmieniony z string na Signal<string>, czyli funkcję. Aby to naprawić, zmień wszystkie odwołania do solvedMessage na solvedMessage().

  1. W pliku secret-message.ts zmień 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 bezpośrednio zmienić jego wartości. Jego wartość jest aktualizowana za każdym razem, gdy zmienia się jeden z sygnałów zależnych (secretMessagedecodedCipher).

Poznaj 2 pozostałe computed() funkcje

  • Zauważ, że w aplikacji masz 2 inne obliczone wartości:

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 określa secretMessage obliczoną superSecretMessage zakodowaną przez cipher, którą gracze muszą rozwiązać.

Pole CipherService określa unsolvedAlphabet obliczoną listę wszystkich liter, których gracz jeszcze nie odgadł. Jest ona wyodrębniana z listy odgadniętych kluczy szyfru w polu decodedCipher.

Weryfikowanie zmian

Teraz, gdy superSecretMessage jest sygnałem, a solvedMessage jest wartością obliczoną, aplikacja powinna działać. Sprawdź funkcje gry:

  1. Przeciągnij i upuść LetterGuessComponent na LetterKeyComponentCipherComponent, aby rozwiązać szyfr i odszyfrować tajną wiadomość.
  2. Sprawdź, jak SecretMessageComponent zmienia się w miarę odszyfrowywania tajnej wiadomości.
  3. Kliknij Dostosuj, aby zmienić nadawcę i wiadomość, a potem kliknij Utwórz i skopiuj URL, aby zobaczyć wartości na ekranie i zmianę adresu URL.
  4. Dodatkowo: skopiuj i wklej adres URL na nowej karcie lub udostępnij go znajomemu i sprawdź, jak nadawca i wiadomość są przechowywane w adresie URL.

GIF z gry Angular Cypher, w której na ekranie jest odszyfrowywana ukryta wiadomość: „Angular Signals are in developer preview in v16 today!” (Sygnały Angulara są dziś dostępne w wersji przedpremierowej dla deweloperów w wersji 16!).

6. Dodaj pierwszy efekt()

Czasami możesz chcieć, aby coś się wydarzyło, gdy sygnał przyjmie nową wartość. Za pomocą effect() możesz zaplanować i uruchomić funkcję obsługi w odpowiedzi na zmianę sygnałów.

Dodawanie konfetti po rozwiązaniu szyfru

Teraz, gdy aplikacja działa, możesz dodać trochę zabawy, wyświetlając konfetti po rozwiązaniu mechanizmu szyfrowania i zdekodowaniu tajnej wiadomości.

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

  1. W pliku cipher.ts zaplanuj efekt, aby 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 aktualizowane są jego zależności.

Weryfikowanie zmian

  • Spróbuj rozwiązać szyfr (wskazówka: możesz zmienić wiadomość na krótką, aby szybciej przetestować rozwiązanie). Wyskakujące konfetti pogratuluje Ci pierwszego effect()!

GIF z gry Angular Cypher, w której na ekranie odszyfrowywana jest ukryta wiadomość, która po rozwiązaniu brzmi „Czas na konfetti!”, a wtedy wystrzeliwują wyrzutnie konfetti.

7. Gratulacje!

Twój szyfr kątowy jest gotowy do odszyfrowywania i udostępniania tajnych wiadomości. Chcesz przekazać wiadomość zespołowi Angular? Oznacz nasze profile w mediach społecznościowych tagiem @Angular, abyśmy mogli je odczytać. 🎉

Rozwiązanie gry Angular Cypher z ukrytą wiadomością na ekranie „Angular Signals are in developer preview in v16 today!”

W zestawie narzędzi Angular masz teraz 3 nowe reaktywne elementy podstawowe, które upraszczają proces tworzenia aplikacji i domyślnie przyspieszają ich działanie.

Więcej informacji

Zapoznaj się z tymi ćwiczeniami:

Zapoznaj się z tymi materiałami: