текст перекладу
Будучи знайомими з кількома фреймворками, ви не єдиний у фронтенд-розробці. Більшість сучасних фреймворків мають спільні основи: архітектуру на основі компонентів, управління станом, маршрутизацію, декларативний рендеринг тощо. Багато з цих концепцій є спільними для фреймворків, і в кінцевому підсумку, це все просто JavaScript.
Якщо ви вже знайомі з React, навчання Vue має бути простим. Давайте порівняємо деякі приклади коду.
Зміст
- Оголошення компонентів
- Шаблони
- Оголошення реактивних даних
- Обробка подій
- Умовний рендеринг
- Прив'язка класів
- Списки
- Комунікація між батьківським і дочірнім компонентами (Props)
- Комунікація з батьківським компонентом (Emits)
- Виведення стану
- Продуктивність компонентів
- Побічні ефекти та спостерігачі
- Хуки життєвого циклу
- Завантаження даних
- Стилі CSS
- Анімації
- Користувацькі хуки та композиційні функції
- Управління глобальним станом
- Інструменти
- Маршрутизація
1. Оголошення компонентів
Перша основна відмінність полягає в оголошенні компонентів. У React компонент — це просто експортована функція, яка має повертати шаблон:
export function MyComponent() {
return
Hello, React World!
; } ```
У **Vue** компоненти оголошуються всередині спеціального файлу з розширенням `.vue`, який називається **Single File Components (SFC)**. SFC має три чітко розмежовані секції:
```
Усі три секції є необов'язковими. Ми дізнаємось більше про них пізніше.
2. Шаблони
Це ще одна суттєва відмінність. Шаблони в попередніх прикладах можуть виглядати як звичайний HTML, але це не так.
React використовує JSX, спеціальний синтаксис для представлення DOM. У ньому є кілька відмінностей, зокрема безліч кастомних правил і можливість писати JavaScript всередині.
З іншого боку, синтаксис шаблонів Vue виглядає значно ближче до чистого HTML, але також підтримує такі функції, як директиви та вирази JavaScript.
Ця відмінність є основою для багатьох наступних секцій.
3. Оголошення реактивних даних
Обидва фреймворки підтримують реактивність. Вони автоматично відстежують зміни та оновлюють усі залежності, зокрема інтерфейс користувача.
У React реактивні дані оголошуються за допомогою хука useState
, який створює змінну стану та відповідну функцію для її оновлення.
import { useState, useEffect } from "react";
export function MyComponent() {
const [count, setCount] = useState(0);
return (
Count: {count}
);
}
У цьому прикладі count
— це реактивні дані, а setCount
— функція, яка оновлює їх. Кожного разу, коли викликається setCount
, React перерендерює компонент, щоб відобразити оновлене значення count
. Для виведення значення змінної або вводу JavaScript в шаблон використовується одинарний синтаксис фігурних дужок { }
.
У Vue реактивні дані керуються за допомогою допоміжних функцій ref
(абоreactive
) з Composition API. Обидві функції повертають реактивну змінну.
Тут count
робиться реактивним за допомогою допоміжної функції ref
. Кожна змінна або функція, оголошена всередині скрипту, буде автоматично доступна в шаблоні. Vue використовує подвійний синтаксис фігурних дужок {{ }}
для інтерполяції.
На відміну від React, де потрібно явно викликати функцію для оновлення стану, Vue відстежує зміни в count
автоматично та перерендерює інтерфейс, коли це необхідно. Усередині секції скрипту ми можемо оновити значення через count.value
, а в шаблонах .value
можна опустити.
**4.
текст перекладу
Обробка подій
У React події обробляються за допомогою атрибутів в стилі camelCase, таких як onClick
.
import { useState } from "react";
export function MyComponent() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
Count: {count}
Increment
); } ```
React приєднує функцію `handleClick` до кнопки. Коли кнопка натискається, функція оновлює стан і перерендерює компонент.
**Vue** використовує ту ж саму ідею, але з дещо іншим синтаксисом.
```
Функція збільшення прив'язана до кнопки за допомогою @click
. Коли кнопка натискається, функція оновлює реактивну змінну, і шаблон автоматично оновлюється.
Ми також можемо використовувати модифікатори, такі як .prevent
, .stop
, .once
і більше для керування поведінкою подій безпосередньо в шаблоні.
Increment
5. Умовний рендеринг
React і Vue по-різному обробляють умовний рендеринг.
У React ми можемо використовувати тернарний оператор або оцінку з коротким замиканням (&&) для умовного рендерингу.
import { useState } from "react";
export function MyComponent() {
const [isVisible, setIsVisible] = useState(true);
return (
{isVisible &&
This is visible
}
{isVisible ?
This is visible
:
This is hidden
}
);
} ```
Для обробки кількох випадків часто використовують вкладений тернарний оператор.
{
condition1 ? (
Condition 1
) : condition2 ? (
Condition 2
) : (
Else
)
} ```
У Vue умовний рендеринг здійснюється за допомогою вбудованих директив v-if
і v-else
.
```
Кілька випадків обробляються за допомогою `v-else-if`.
Condition 1
Condition 2
Else
```
6. Прив'язка класів
Тернарний оператор також можна використовувати для умовного застосування класу в React.
import { useState } from "react";
export function MyComponent() {
const [isVisible, setIsVisible] = useState(true);
return (
This is a conditionally styled message.
);
} ```
У **Vue** синтаксис трохи інший, де директива класів приймає об'єкт як параметр.
текст перекладу
Списки
Ітерації в React виконуються всередині інтерполяції за допомогою методу JavaScript .map()
.
export function MyComponent() {
const items = ["Item 1", "Item 2", "Item 3"];
return (
{items.map((item, index) => (
{item}
))}
);
} ```
У **Vue** ми використовуємо `v-for`, іншу вбудовану директиву.
```
8. Комунікація з батьківського до дочірнього компонента (Props)
Обидва фреймворки використовують концепцію props
для передачі даних між компонентами.
У React props
передаються як атрибути в шаблоні. Вони доступні тільки для читання та можуть бути доступні як аргументи в дочірньому компоненті.
export function ParentComponent() {
const message = "Hello from React!";
return ;
}
export function ChildComponent({ message }) {
return
{message}
;
} ```
Та сама ідея у Vue, але дочірній компонент має явно оголосити кожен `prop`, використовуючи допоміжну функцію `defineProps`. Кожен `prop` можна типізувати і [мати необов'язковий валідатор або значення за замовчуванням](https://vuejs.org/guide/components/props#prop-validation).
```
```
## **9. Комунікація з дочірнього до батьківського компонента (Emits)**
`Props` дозволяють передавати дані з батьківського до дочірнього компонента, але як бути в зворотному напрямку?
У React немає спеціальної функціональності для цього. Натомість ми можемо передати функцію зворотного виклику як `prop` дочірньому компоненту, який може використовувати її для оновлення стану батьківського компонента.
export function ParentComponent() {
const handleCustomEvent = (message) => {
console.log(message);
};
return ;
}
export function ChildComponent({ onCustomEvent }) {
return (
onCustomEvent("Hello from the child!")}>
Click Me
);
} ```
У Vue використовується інша модель. Дочірні компоненти можуть викидати (emit) власні події за допомогою допоміжної функції defineEmits
.
```
```
Дочірній компонент викидає подію customEvent
з деякими необов'язковими даними, а батьківський компонент слухає її за допомогою директиви @customEvent
. Допоміжна функція defineEmits
забезпечує типову безпеку і чіткість для оголошених подій.
10. Виведений стан (Derived State)
У React виведений стан обчислюється за допомогою хуку useMemo
, який мемоізує результат, щоб уникнути непотрібних перерахунків.
import { useState, useMemo } from "react";
export function MyComponent() {
const [firstName, setFirstName] = useState("Frodo");
const [lastName, setLastName] = useState("Baggins");
const fullName = useMemo(() => `${firstName} ${lastName}`, [firstName, lastName]);
return
Full Name: {fullName}
;
} ```
**Vue** використовує обчислювані властивості (computed properties).
текст перекладу
## 11. Продуктивність компонентів
Важливо знати, що в **React** компоненти перерендерюються після кожної зміни стану або `prop`. Хоча це зазвичай ефективно, це може стати дорогим процесом, коли йдеться про складні обчислення або великі компоненти. Щоб уникнути непотрібних перерахунків, React надає інструменти, такі як `React.memo`, `useMemo` та `useCallback`.
`React.memo` запобігає перерендеренню функціонального компонента, якщо його `props` не змінилися.
import React, { useState } from "react";
const ChildComponent = React.memo(({ count }) => {
console.log("Child rendered");
return
Count: {count}
;
});
export function ParentComponent() {
const [count, setCount] = useState(0);
return (
setCount(count + 1)}>Increment
);
} ```
useMemo
запобігає перерахунку дорогих функцій, якщо їх залежності не змінилися. (Див. також розділ про виведений стан)
import { useState, useMemo } from "react";
export function MyComponent() {
const [count, setCount] = useState(0);
const expensiveCalculation = useMemo(() => {
console.log("Calculating...");
return count * 2;
}, [count]);
return (
Count: {count}
Calculated: {expensiveCalculation}
setCount(count + 1)}>Increment
);
} ```
`useCallback` мемоізує функції, щоб запобігти їх повторному створенню, що особливо корисно при передачі функцій зворотного виклику як `props`.
import { useState, useCallback } from "react";
export function MyComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []);
return (
Count: {count}
Increment
);
} ```
Код для виконання тих самих оптимізацій у Vue виглядає так. У Vue багато оптимізацій обробляються автоматично його системою реактивності. Вона відстежує залежності для реактивних змінних і перераховує їх лише тоді, коли це необхідно. Тому немає потреби в ручному налаштуванні продуктивності на низькому рівні.
12. Побічні ефекти та спостерігачі (Watchers)
У React для моніторингу певних значень і виконання функцій зворотного виклику при зміні цих значень використовується useEffect
.
import { useState, useEffect } from "react";
export function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count changed to ${count}`);
}, [count]);
return (
Count: {count}
setCount(count + 1)}>Increment
);
} ```
Масив залежностей `[count]` гарантує, що ефект буде виконаний лише коли зміниться значення `count`.
У Vue для цього є спостерігачі (watchers).
```
Функція зворотного виклику буде виконана кожного разу, коли зміниться значення count
.
Є ще
watchEffect
, але він не такий крутий!
текст перекладу13. Хуки життєвого циклу
Хук useEffect
, у поєднанні з порожнім масивом залежностей, можна використовувати для виконання коду під час ініціалізації компонента або перед його знищенням.
import { useEffect } from "react";
export function MyComponent() {
useEffect(() => {
console.log("Component mounted");
return () => {
console.log("Component unmounted");
};
}, []);
return
My React Component
;
} ```
Vue надає спеціалізовані хуки, такі як `onMounted` та `onUnmounted` для етапів [життєвого циклу компонента](https://vuejs.org/guide/essentials/lifecycle).
```
14. Завантаження даних
Обидва фреймворки часто використовують сторонні бібліотеки, такі як Axios, React Query, або Vue Query для завантаження даних. Однак основна логіка залишається подібною до використання вбудованого методу fetch
. Ось типовий випадок використання:
У React завантаження даних обробляється всередині хука useEffect
.
import { useState, useEffect } from "react";
export function MyComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const response = await fetch("https://api.example.com/data");
const result = await response.json();
setData(result);
setLoading(false);
}
fetchData();
}, []);
if (loading) return
Loading...
;
return
Data: {data.message}
;
} ```
У **Vue** завантаження даних можна обробляти безпосередньо під час ініціалізації компонента.
```
15. CSS стилі
Існує безліч способів стилізувати компонент React. Від інлайнових стилів до CSS-модулів і бібліотек, таких як Emotion та Styled Components, усе може стати досить складним і, ймовірно, потребує окремої статті. Ми розглянемо лише найпоширеніші варіанти використання, але ви можете більше дізнатися про опції стилізації в React.
Використання інлайнових стилів:
export function MyComponent() {
const style = {
color: "blue",
fontSize: "20px",
};
return
Styled Text
;
} ```
Використання зовнішніх CSS файлів:
import "./styles.css";
export function MyComponent() {
return
Styled Text
;
} ```
Зверніть увагу, що в React використовується
className
, а неclass
, щоб уникнути конфліктів з зарезервованими ключовими словами JavaScript.
текст перекладу18. Особливості JSX
Це одна з особливостей JSX.
Використання CSS Модулів:
import styles from "./MyComponent.module.css";
export function MyComponent() {
return
Styled Text
;
} ```
CSS Модулі автоматично обмежують застосування стилів поточним компонентом, і вони наразі є дуже популярним вибором. У **Vue** стилі — це одна з трьох секцій в компоненті з єдиним файлом.
```
Атрибут scoped
гарантує, що CSS впливатиме лише на поточний компонент. Препроцесори, такі як Scss
, Less
, Stylus
або postcss
, також підтримуються через додавання атрибута lang
до тега стилів. Scss
— це популярний вибір.
```
> Атрибут `lang` також можна використовувати для інших секцій, щоб конвертувати ваші скрипти в `typescript` або ваш шаблон в `pug`, наприклад.
## 16. Анімації
React не займається анімаціями, але їх можна створювати в React за допомогою сторонніх бібліотек, таких як [**Framer Motion**](https://www.npmjs.com/package/framer-motion), [**React Spring**](https://www.react-spring.dev/), або навіть CSS-переходів. Хоча у Vue також підтримується використання сторонніх бібліотек, він пропонує потужний вбудований механізм, який може обробляти як прості, так і складні анімації. Обгортання елемента в компонент `transition` або `transition-group` автоматично застосовує класи під час анімації, які можна націлювати за допомогою CSS для створення власних ефектів.
Простий приклад:
```
[ ## Vue 3 Real Life Transitions and Micro-Interactions
Vue надає простий і елегантний спосіб обробки анімацій. Ви можете легко застосувати їх, додавши …
fadamakis.com ](/vue-js-real-life-transitions-and-micro-interactions-e86bd51301b8?source=post_page-----602d0f98755a--------------------------------)
17. Користувацькі хуки та композиційні функції
Ось де відбувається вся магія*.
- реалізація складної бізнес-логіки, яка точно викличе головний біль
У React користувацькі хуки — це просто функції JavaScript, які можуть зберігати стан і функції. Вони можуть використовувати інші хуки, такі як useState
або useEffect
.
import { useState } from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return { count, increment, decrement };
}
export function MyComponent() {
const { count, increment, decrement } = useCounter();
return (
Count: {count}
Increment Decrement
);
} ```
У **Vue** композиційні функції виконують ту ж саму роль.
текст перекладу
## **Користувацькі хуки та композиційні функції (Composables)**
Вони зберігають стан та повторно використовувану логіку.
// useCounter.js
import { ref } from "vue";
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => count.value++;
const decrement = () => count.value--;
return {
count,
increment,
decrement
};
}
```
[
Композиційні функції (Composables) як управління станом у Vue3
Спільне використання стану між компонентами у світі Vue 3 стало легшим, завдяки композиційним функціям. Ця нова парадигма…
fadamakis.com
](/composables-as-state-management-in-vue3-ad59837cad48?source=post_page-----602d0f98755a--------------------------------)
18. Глобальне управління станом
Ще одна складна тема, яка могла б бути окремою статтею. Ми зосередимося на базовому випадку, але ви можете дізнатися більше про управління станом у React або Vue, якщо хочете більше інформації.
У React глобальне управління станом зазвичай здійснюється за допомогою бібліотек, таких як Redux, Zustand або вбудованого Context API. Ось приклад використання останнього.
import { createContext, useContext, useState } from "react";
const CounterContext = createContext();
export function CounterProvider({ children }) {
const [count, setCount] = useState(0);
return (
{children}
);
}
export function useCounter() {
return useContext(CounterContext);
}
// Приклад використання:
export function MyComponent() {
const { count, setCount } = useCounter();
return (
Count: {count}
setCount(count + 1)}>Increment
);
} ```
У **Vue** новішою та офіційно рекомендованою бібліотекою для управління станом є [Pinia](https://pinia.vuejs.org/).
import { defineStore } from "pinia";
export const useCounterStore = defineStore("counter", () => {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
});
```
```
Зверніть увагу, як це схоже на композиційну функцію? Тому що це вона! Основна перевага використання Pinia — легкість перевірки та відлагодження за допомогою Vue DevTools.
## 19. Інструменти
Інструментів було б дуже багато кілька років тому. Але на щастя, зараз **Vite** домінує в обох екосистемах і широко вважається найкращим вибором. Він надає швидкі збірки, гарячу заміну модулів, розподіл коду та плагіни, і його набагато легше налаштовувати.
npm create vite@latest my-react-app -- --template react
```
npm create vite@latest my-vue-app -- --template vue
текст перекладу
## Маршрутизація (Routing)
Обидва фреймворки використовують зовнішні бібліотеки для маршрутизації, але їх підходи відрізняються за синтаксисом та структурою.
**React** використовує [**React Router**](https://reactrouter.com/). Конфігурація нагадує оголошення компонента і може здаватися трохи незвичною на перший погляд.
import { BrowserRouter as Router, Route, Routes, Link } from "react-router-dom";
export function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
);
}
function Home() {
return
;
}
function About() {
return
;
}
```
Vue використовує Vue Router. Конфігурація більш декларативна, визначаючи зіставлення маршрутів у конфігураційному об'єкті.
import { createRouter, createWebHistory } from "vue-router";
import Home from "./components/Home.vue";
import About from "./components/About.vue";
const routes = [
{ path: "/", component: Home },
{ path: "/about", component: About },
];
export const router = createRouter({
history: createWebHistory(),
routes,
});
```
`<router-link>` та `<router-view>` доступні глобально і не потребують явного імпорту.
## Висновок
Тепер настав час для питання на мільйон доларів. Який з фреймворків кращий?
Ну...
> Все залежить від того, що вам важливіше.
Навчання API нового фреймворка займає лише кілька тижнів. Справжнім викликом є реалізація складної бізнес-логіки всередині користувацьких хуків (custom hooks) або композиційних функцій (composables), управління станом і... вирівнювання div-ів. І жоден з цих аспектів не є частиною жодного з фреймворків.
Для мене вибір очевидний, і він залежить від того, чи **любите ви писати JSX чи ні**. React значною мірою покладається на нього, тоді як Vue слідує більш декларативному, шаблонно орієнтованому синтаксису.
Крім того, різниці незначні, якщо подивитися на картину в цілому. Обидва фреймворки потужні і здатні впоратися з будь-яким масштабним додатком. В кінці кінців, важливо не стільки з яких інструментів ви користуєтесь, скільки з того, як ви їх використовуєте. Тому використовуйте їх добре!
![pic](https://drive.javascript.org.ua/d90d204e6a1_QXb_ojcVnekAmWDeHHkrmA_png)
_Вибору немає._
Перекладено з: [Learning Vue for React Developers](https://fadamakis.medium.com/learning-vue-for-react-developers-602d0f98755a)