Frontend, Juniors, Mobile

Napisałem tę samą aplikację w Vue i Reactcie. Zobaczcie różnice

W obecnej pracy używam Vue, dzięki czemu mam pojęcie jak działa od środka. Mimo to, byłem ciekaw, jak wygląda stworzenie tej samej aplikacji w innej technologii, a dokładniej w Reactie. Właśnie to chcę pokazać w poniższym artykule.


Sunil Sandhu. Developer, Editor of JSIPE, Daydreamer. Współautor cyklu artykułów na medium.com pt. Javascript In Plain English. W serii artykułów doświadczeni developerzy dzielą się wskazówkami dla juniorów i pokazują różne aspekty pracy programisty. Bardzo polecamy ten cykl. Poniższy artykuł został przetłumaczony za zgodą autora.


Przyjrzałem się bliżej Reactowi, przeczytałem artykuły na jego temat i obejrzałem tutoriale. Pomimo tego, że React pokazano mi ze świetnej strony, ciekawiło mnie to, czym różni się od Vue. Przez pojęcie “różni się” nie miałem na myśli tego, jaki ma stosunek do renderowania stron. Chciałem, by ktoś wytłumaczył mi, jak wygląda kod i w jaki sposób działa.

Zajrzałem więc do sieci w poszukiwaniu artykułu, który wyjaśni różnice komuś, kto nie zna ani Vue, ani Reacta (ani w ogóle nie jest web developerem), by w pełni zrozumiał jak obydwie biblioteki działają. Niestety nie znalazłem takiego tekstu. Doszedłem więc do wniosku, że sam zostanę taką osobą, która na konkretnym przykładzie pokaże podobieństwa i różnice. W moim przekonaniu, udokumentowałem cały proces tworzenia tej samej aplikacji w Vue i osobnej w Reactie. Oto rezultat mojej pracy.

Zdecydowałem się zbudować standardową aplikację z listą to-do, która pozwoli użytkownikowi dodawać i usuwać zadania na liście. Obydwie aplikacje będą używać CLIsa (dla Reacta: create-react-app, a dla Vue: vue-cli). CLI, czyli Command Line Interface.

Poniżej zobaczycie jak wyglądał efekt końcowy zbudowania dwóch tych samych aplikacji w różnych technologiach.

Warto zaznaczyć, że kod CSS dla tych dwóch aplikacji jest dokładnie taki sam, są jednak różnice dotyczące tego, gdzie został ulokowany. Spójrzmy na to, jak wygląda struktura tych dwóch aplikacji.

Zauważyliście pewnie, że struktura dwóch aplikacji jest prawie identyczna. Jedyna różnica polega na tym, że React ma trzy pliki CSS, a Vue nie ma żadnego. Powodem tego jest to, że w CLI’sie Reacta (create-react-app) znajdują się pliki zachowujące style, a Vue CLI adoptuje wszystkie. Mimo to obydwie osiągają ten sam cel.

Zanim przejdziemy dalej, spójrzmy szybko jak wygląda typowy component napisany w Vue i w Reactcie.

Vue po lewej. React po prawej

Teraz możemy spokojnie przejść do najciekawszej części artykułu: czyli szczegółowego wyjaśnienia różnic, o których piszę od początku.

W jaki sposób mutujemy dane?

Na początku wyjaśnijmy, co znaczy pojęcie “mutowanie danych”? Brzmi dość technicznie, prawda? A mutowanie danych znaczy zmienianie danych, które przechowujemy. Jeśli zatem chcemy zmienić imię użytkownika z John na Mark, podejmiemy się właśnie mutacji danych. Ten przypadek pokazuje też kluczową różnicę pomiędzy Reactem i Vue. Podczas gdy Vue zasadniczo tworzy obiekt danych, w którym mogą być one swobodnie aktualizowane, React tworzy obiekt stanu, który do wykonania aktualizacji wymaga więcej pracy — tym zajmiemy się trochę później. Najpierw przyjrzyjmy się obiektowi danych z Vue i obiektowi stanu z React:

Vue z lewej, React z prawej

Jak widzisz, zmieniamy te same dane, ale w zupełnie inny sposób. Załóżmy, że mamy daną: name: ‘Sunil’. W Vue, odwołamy się do niej wywołując komendę this.name. Możemy też zaktualizować imię wpisując: this.name = ‘John’. W Reactcie, tą samą daną wywołamy za pomocą: this.state.name. Różnica polega jednak na tym, że w Reactcie nie napiszemy: this.state.name = ‘John’, ponieważ nie możemy tworzyć tego typu mutacji w Reactcie. Dlatego imię możemy zmienić wpisując: this.setState({name: ‘John’}).

Mimo że chcieliśmy dokonać tej samej zmiany, co w Vue, w przypadku Reacta musieliśmy wykonać więcej pracy.

Skoro mamy już temat mutacji za sobą, przejdźmy do innych przykładów, w jaki sposób możemy dodawać elementy do obu aplikacji.

W jaki sposób tworzymy nowe elementy w liście To Do?

React:

createNewToDoItem = () => {
    this.setState( ({ list, todo }) => ({
      list: [
          ...list,
        {
          todo
        }
      ],
      todo: ''
    })
  );
};

Wyjaśnienie:

W Reactcie naszym polem wyjściowym jest value. Dzięki niemu automatycznie aktualizujemy różne funkcje połączone za pomocą two-way binding. Tworzymy tę formę dwukierunkowego powiązania poprzez dołączenie dodatkowego event listenera OnChange do pola wejściowego. Rzućmy okiem na pole wejściowe, aby zobaczyć, co się dzieje:

<input type="text" 
           value={this.state.todo} 
           onChange={this.handleInput}/>

Funkcja handleInput jest uruchamiana za każdym razem, gdy zmienia się wartość pola wejściowego. Aktualizuje todo, które znajduje się wewnątrz obiektu stanu, ustawiając go na to, co znajduje się w polu wejściowym. Funkcja ta wygląda następująco:

handleInput = e => {
  this.setState({
    todo: e.target.value
  });
};

Jeśli użytkownik aplikacji naciśnie + w aplikacji, by dodać zadanie do listy, funkcja createNewToDoItem uruchomi this.setState i utworzy funkcję. Będzie miała ona dwa parametry: list i todo (druga będzie aktualizowana przez funkcję handleInput).

Na koniec ustawiamy todo jako pusty ciąg, który automatycznie aktualizuje value w polu input.

Vue:

createNewToDoItem() {
    this.list.push(
        {
            'todo': this.todo
        }
    );
    this.todo = '';
}

Wyjaśnienie:

W Vue, nasz input nazywany jest v-model. Pozwala on na dokonanie dwukierunkowego wiązania. Rzućmy okiem na input, a później wyjaśnię, jak działa.

<input type="text" v-model="todo"/>

V-Model wiąże wejście tego pola z kluczem, który mamy w naszym obiekcie danych o nazwie toDoItem. Kiedy strona ładuje się, musimy ustawić ToDoItem na pusty ciąg, jako taki: todo: ”. Jeśli było tam już trochę danych, takich jak todo: „dodaj tu trochę tekstu”, nasze pole wejściowe załadowałoby się, dodając tekst już w polu wejściowym. W każdym razie, wracając do posiadania go jako pustego ciągu, dowolny tekst, który wpiszemy w polu wejściowym zostanie powiązany z wartością dla todo. Jest to skutecznie dwukierunkowe wiązanie (pole wejściowe może aktualizować obiekt danych, a obiekt danych może aktualizować pole wejściowe).

Wracając do createNewToDoItem(), widzimy, że wciskamy zawartość todo do tablicy list, a następnie aktualizujemy todo do pustego łańcucha.

Jak usunąć zadanie z listy?

React:

deleteItem = indexToDelete => {

   this.setState(({ list }) => ({
     list: list.filter((toDo, index) => index !== indexToDelete)
   }));
};

Wyjaśnienie:

Podczas gdy funkcja deleteItem znajduje się wewnątrz ToDo.js, bardzo łatwo mogłem odwołać się do niej w ToDoItem.js przez przekazanie funkcji deleteItem () jako podpory w <ToDoItem /> tak:

<ToDoItem deleteItem={this.deleteItem.bind(this, key)}/>

Po pierwsze przekazuje tę funkcję, aby była dostępna dla dziecka. Wiążemy także this, i przekazujemy kluczowy parametr, by móc rozróżnić, który ToDoItem próbuje usunąć po kliknięciu. Następnie wewnątrz komponentu ToDoItem wykonujemy te czynności:

<div className=”ToDoItem-Delete” onClick={this.props.deleteItem}>-</div>

Jedyne, co musiałem zrobić, aby odwołać się do funkcji znajdującej się wewnątrz komponentu nadrzędnego, to odwołanie do this.props.deleteItem.

Vue:

onDeleteItem(todo){
 this.list = this.list.filter(item => item !== todo);
}

Wyjaśnienie:

Vue wymaga od nas nieco innego podejścia. Właściwie musimy przejść przez trzy kroki:

Po pierwsze, wywołać poniższą funkcję:

<div class=”ToDoItem-Delete” @click=”deleteItem(todo)”>-</div>

Następnie musimy utworzyć funkcję emitującą jako metodę wewnątrz komponentu potomnego (w tym przypadku ToDoItem.vue), która wygląda następująco:

deleteItem(todo) {
   this.$emit('delete', todo)
}

Na pewno zauważyłeś, że faktycznie odwołujemy się do funkcji, kiedy dodajemy ToDoItem.vue do ToDo.vue:

<ToDoItem v-for="todo in list"
         :todo="todo"
         @delete="onDeleteItem" // <-- this :)
         :key="todo.id" />

Jest to tak zwany niestandardowy detektor zdarzeń. Wysłuchuje każdej okazji, w której emitowany jest sygnał z łańcuchem „delete”. Jeśli to usłyszy, uruchomi funkcję o nazwie onDeleteItem. Znajduje się ona w ToDo.vue, a nie w ToDoItem.vue. Ta funkcja, jak wymieniono wcześniej, po prostu filtruje tablicę todo wewnątrz obiektu danych, aby usunąć element, który został kliknięty.

Warto też zaznaczyć, że w przypadku Vue mogłem łatwo napisać $emit jako część @click, na przykład w ten sposób:

<div class=”ToDoItem-Delete” @click=”$emit(‘delete’, todo)”>-</div>

To zredukuje liczbę kroków z trzech do dwóch.

W skrócie, komponenty potomne w React będą miały dostęp do funkcji rodzicielskich za pośrednictwem this.props (pod warunkiem, że pominiesz rekordy, co jest dość standardową praktyką i natkniesz się na to wiele razy w innych przykładach React), podczas gdy w Vue, musisz emitować zdarzenia od dziecka, które zwykle będą gromadzone wewnątrz komponentu macierzystego.

W jaki sposób przekazujemy event listeners – React i Vue?

React:

Event listeners dla prostych rzeczy takich jak klikanie działa… prosto. Poniżej przykład jak stworzyliśmy event dla przycisku do tworzenia nowych zadań na liście ToDo:

<div className=”ToDo-Add” onClick={this.createNewToDoItem}>+</div>

Poszło super szybko i wygląda to nieźle. Jak wspomniałem wyżej, Vue trochę więcej czasu zajęła konfiguracja detektora zdarzeń do obsługi po naciśnięciu przycisku Enter. Wymagało to zasadniczo ze zdarzenia onKeyPress, który wykorzystaliśmy do obsłużenia przez wejściowy znacznik:

<input type=”text” onKeyPress={this.handleKeyPress}/>

Ta funkcja zasadniczo uruchamia funkcję createNewToDoItem za każdym razem, gdy rozpoznano naciśnięcie klawisza „Enter”:

handleKeyPress = (e) => {
if (e.key === ‘Enter’) {
this.createNewToDoItem();
}
};

Vue:

W Vue jest to jeszcze prostsze. Po prostu używamy symbolu @, a następnie rodzaju detektora zdarzeń, który chcemy wstawić. Aby na przykład dodać detektor zdarzeń kliknięcia, możemy napisać:

<div class=”ToDo-Add” @click=”createNewToDoItem()”>+</div>

Uwaga: @click jest skrótem do pisania v-on: kliknij. Fajną rzeczą w przypadku detektorów zdarzeń Vue jest to, że istnieje również wiele rzeczy, do których można się do nich podłączyć, na przykład .once, która zapobiega uruchamianiu detektora zdarzeń więcej niż jeden raz. Istnieje również wiele skrótów, jeśli chodzi o pisanie konkretnych detektorów zdarzeń, do obsługi naciśnięć klawiszy. Zauważyłem, że stworzenie detektora zdarzeń w React wymaga nieco więcej czasu, aby utworzyć nowe rzeczy do zrobienia po naciśnięciu przycisku Enter. W Vue udało mi się po prostu napisać:

<input type=”text” v-on:keyup.enter=”createNewToDoItem”/>

W jaki sposób przekazujemy dane do komponentu potomnego?

React:

W React’cie, robimy to w ten sposób:

<ToDoItem key={key} item={todo} />

Widzimy tutaj dwa rekwizyty przekazane do komponentu ToDoItem. Od tego momentu możemy teraz odwoływać się do nich w komponencie potomnym za pośrednictwem this.props. Aby uzyskać dostęp do obiektu item.todo, po prostu nazywamy this.props.item.

Vue:

A w Vue, robimy to tak:

<ToDoItem v-for="todo in list"
           :todo="todo"
           :key="todo.id"
           @delete="onDeleteItem" />

Gdy to zrobimy, przekazujemy je do tablicy rekwizytów w komponencie potomnym jako: props: [’id’, 'todo’]. Można je następnie przywoływać w dziecku przez ich nazwy, więc „id” i „todo„.

W jaki sposób wysyłamy dane z powrotem do komponentu nadrzędnego?

React:

Najpierw przekazujemy tę funkcję do komponentu potomnego, określając ją jako rekwizyt w miejscu, w którym nazywamy komponent potomny. Następnie dodajemy wywołanie funkcji na dziecko przy użyciu dowolnych metod, takich jak onClick, przez odwołanie this.props.jakkolwieknazwiemytefunkcje. Spowoduje to uruchomienie funkcji znajdującej się w składniku macierzystym. Przykład tego całego procesu znajduje się w sekcji „Jak usunąć zadanie z listy„.

Vue:

W naszym komponencie potomnym po prostu piszemy funkcję, która wysyła wartość z powrotem do funkcji nadrzędnej. W naszym składniku macierzystym zapisujemy funkcję, która nasłuchuje, kiedy ta wartość jest emitowana, co może wywołać wywołanie funkcji. Przykład tego całego procesu znajduje się w sekcji „Jak usunąć zadanie z listy„.

Mamy to!

Przyjrzeliśmy się temu, jak dodawać, usuwać i zmieniać dane, przekazywać dane w postaci rekwizytów z rodzica na dziecko i przesyłać dane od dziecka do rodzica w postaci detektorów zdarzeń. Oczywiście, istnieje wiele innych drobnych różnic i dziwactw między React i Vue, ale mam nadzieję, że treść tego artykułu może służyć jako chociaż jako podstawa do zrozumienia, w jaki sposób obie struktury radzą sobie z tymi samymi zadaniami.

Poniżej znajdziecie też linki do obydwu aplikacji:

Vue ToDo: https://github.com/sunil-sandhu/vue-todo

React ToDo: https://github.com/sunil-sandhu/react-todo.

baner

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://geek.justjoin.it/aplikacja-vue-react/" order_type="social" width="100%" count_of_comments="8" ]