Napisałem wcześniej podobne artykuły na temat AngularJS (link) i Angular2 (link). Wiedza tam zawarta jest w dużej części uniwersalna i możesz chcieć do nich zajrzeć.
Komunikacja w React.js
React to prosta biblioteka. Zasadniczo nie obchodzi jej w jaki sposób projektujesz architekturę swojej aplikacji. Ale zawarto w niej mechanizm na przekazywanie informacji z jednego komponentu do drugiego — z rodzica do dziecka — przy pomocy propsów. Tak jak robiliśmy to do tej pory. Ale przekazywać można nie tylko dane, ale też funkcje ;) W tym wpisie fragmenty kodu, a całość razem z testami znajdziesz na moim GitHubie: mmiszy/typeofweb-kurs-react/tree/part-4.
Rodzic ➜ Dziecko: Propsy
Rodzic przekazuje do swoich dzieci dane. Przykładowo: Aplikacja zawiera listę kontaktów, które muszą zostać przekazane do komponentu-dziecka, który je wyświetli. Znana sytuacja, prawda? ;)
React informuje nas, że propsy się zmieniły poprzez funkcję componentWillReceiveProps(nextProps)
— dzięki czemu można zareagować na zmiany danego propsa. Ale raczej tego nie rób. Bo naprawdę rzadko jest to potrzebne. Troszkę więcej o tym w jednym z poprzednich wpisów:
W zasadzie to cała filozofia.
Dziecko ➜ Rodzic: Propsy (callback)
A teraz inna sytuacja. Coś się wydarzyło w komponencie-dziecku i musisz poinformować o tym rodzica. Przykładowo: Na naszej liście kontaktów, użytkownik zaznaczył kontakt, a rodzic musi wiedzieć, który kontakt został zaznaczony. Jak to zrobić?
React nie ma two-way data bindingu (jak AngularJS, Angular czy Vue). W tym przypadku to dobrze — bo komunikacja za pośrednictwem tego sposobu często prowadzi do bałaganu. Reactowy sposób jest inny: Rodzic może przekazać do dziecka funkcję. Następnie dziecko wywoła tę funkcję, gdy zechce poinformować rodzica o zmianach. To jest tak proste jak brzmi. Na przykładzie z listą kontaktów:
Dodaję nowe pole do state
w App
: selectedUser
— będę tutaj przechowywał użytkownika, który został zaznaczony. Następnie wyświetlam go wewnątrz funkcji render
. Pozostały kod pozostawiam bez zmian:
class App extends React.Component {
constructor() {
super();
this.state = {
filteredUsers: allUsers,
selectedUser: null // tutaj
};
}
render() {
return (
<div>
{this.state.selectedUser}
{/* … */}
</div>
);
}
}
Teraz czas na przekazanie funkcji do dziecka. Tworzę więc nową funkcję w tym komponencie i przekazuję ją niżej:
onUserSelected = (selectedUser) => {
this.setState({
selectedUser
});
}
render() {
return (
<div>
{/* … */}
<UsersList userSelected={this.onUserSelected} users={this.state.filteredUsers} />
</div>
);
}
Teraz modyfikuję UsersList
i wywołuję w nim userSelected
gdy użytkownik kliknie na kontakt:
<li onClick={userSelected.bind(null, user)} key={user}>{user}</li>
Dowolny komponent ➜ Inny Komponent
Tutaj magia Reacta się kończy ;) No, prawie, ale na temat context
opowiem innym razem. Załóżmy na razie, że nie istnieje ;) Jak więc skomunikować ze sobą dwa komponenty, które leżą sobie gdziekolwiek w aplikacji? Na dowolny znany Ci sposób. To nie żart. Oto kilka wskazówek:
- stwórz funkcję / klasę / obiekt — tzw. serwis, który posłuży Ci do komunikacji. Zaimportuj i użyj go w obu komponentach.
- Przechowuj w nim dane lub wywołuj funkcje — podobnie jak w przypadku komunikacji rodzic ⟺ dziecko
- Przyda Ci się znajomość wzorców projektowych, np. wzorca obserwatora. Więcej na temat samej koncepcji pod koniec mojego innego wpisu (link). Może ten gist (link) się nada?
- Możesz użyć gotowych paczek, typu EventEmitter3 (link) lub podobnych.
Flux, Redux, MobX i co tam jeszcze…
Są też pewne ciekawe, rozbudowane i popularne rozwiązania: Architektura Flux i wywodzący się z niej słynny Redux, a także MobX. No i inne podobne biblioteki. Popełniłem już wcześniej jeden wpis na temat Fluksa i Reduksa od strony architektury. Jeśli hasła CQRS albo Event Sourcing nie są Ci obce to śmiało czytaj:
Natomiast w kontekście Reacta — wrócę do tego, obiecuję ;) To temat pierwszy albo drugi wpis po tym! zapisz się na szkolenie z React.
Podsumowanie
Teraz już wiesz jak komponenty rozmawiają ze sobą. Wiedza na temat architektury aplikacji i wzorców projektowych przydaje się zawsze, niezależnie od frameworka, z którego korzystasz. Także tutaj. Ponownie — cały kod wraz z testami jest dostępny na moim GitHubie: https://github.com/typeofweb/typeofweb-kurs-react/tree/part-4
Jeśli chcesz na bieżąco dowiadywać się o kolejnych częściach kursu React.js to koniecznie śledź mnie na Facebooku i zapisz się na newsletter.
Ćwiczenie
Ćwiczenie: Użyj biblioteki EventEmitter3 aby skomunikować ze sobą App
i UsersList
w powyższym przykładzie (bez przekazywania funkcji jako props). Czy udało Ci się bez problemu? Napisz w komentarzu!