1. Zanim zaczniesz
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()
ieffect()
. - 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.
Wymagania wstępne
- znajomość Angulara i Typescripta,
- Zalecane: obejrzyj wykład Rethinking Reactivity with Signals, aby dowiedzieć się więcej o bibliotece Angular Signals.
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:
- 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
- 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:
- Otwórz nową kartę przeglądarki i wejdź na stronę https://github.com/angular/codelabs/tree/signals-get-started.
- Wykonaj fork repozytorium i sklonuj je, a następnie użyj polecenia
cd codelabs/
, aby przejść do repozytorium. - Sprawdź gałąź kodu startowego za pomocą polecenia
git checkout signals-get-started
. - Otwórz kod w VSCode lub ulubionym środowisku IDE.
- Aby zainstalować zależności wymagane do uruchomienia serwera, użyj polecenia
npm install
. - Aby uruchomić serwer, użyj polecenia
ng serve
. - 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.
Na początek zapoznaj się z gotową wersją elementów, które będziesz tworzyć: Angular Signals Cypher.
- Zobacz kodowany komunikat na ekranie.
- Przeciągnij i upuść przycisk z literą na klawiaturze, aby odszyfrować i odkodować tajną wiadomość.
- Gdy operacja się uda, sprawdź, jak wiadomość jest aktualizowana, aby zdekodować dalszą część tajnej wiadomości.
- 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.
- 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.
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:
- 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
z @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 superSecretMessage
z string
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.
- W plikach
secret-message.ts
iservice.message.ts
zaktualizuj wszystkie odwołania dosuperSecretMessage
nasuperSecretMessage()
:
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ę nowysuperSecretMessage
.
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()
:
- W pliku
service.message.ts
użyj biblioteki Signals, aby uczynić elementsolvedMessage
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
z @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()
.
- W pliku
secret-message.ts
zaktualizuj wszystkie odwołania dosolvedMessage
nasolvedMessage()
:
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 (secretMessage
i decodedCipher
).
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:
- Przeciągnij i upuść
LetterGuessComponent
doLetterKeyComponent
wCipherComponent
, aby odszyfrować i odkodować tajną wiadomość. - Zobacz, jak
SecretMessageComponent
zmienia się wraz z dekodowaniem kolejnych części tajnej wiadomości. - Aby zmienić wartości nadawcy i wiadomości, kliknij Dostosuj, a potem Utwórz i skopiuj adres URL.
- 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.
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()
- 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()
i 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.
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ć. 🎉
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:
- Pierwsze kroki z samodzielnymi komponentami
- Tworzenie aplikacji internetowej za pomocą Angulara i Firebase
Przeczytaj te materiały:
- Angular.io
- Rethinking Reactivity with Signals (Google I/O 2023)
- Co nowego w Angular (Google I/O 2023)