В настоящее время на рынке существует множество Javascript фронтенд-фреймворков, которые наделали много шума. Известные 3 — Angular, React и Vue (Svelte все еще продолжает гонку), также следует отметить MeteorJS, Ionic. Конечно, есть фронтенд-фреймворки более высокого уровня, такие как NestJS, NextJS и NuxtJS, но давайте оставим их для другого обсуждения.

Целью написания этой статьи является не сравнение двух отличных фреймворков для современного веб-приложения, а выделение особенностей обоих, которые дают большой опыт разработчикам, и возможность обмена знаниями между ними, так что вам не придется начинать с нуля.

Дисклеймер: Я имею профессиональный опыт работы с React более двух лет (и продолжаю это делать на момент написания этой статьи), а Vue только что задействовал в своем новом проекте, поэтому сравнение может быть не совсем справедливым, но все-таки надеюсь, что смогу сделать все возможное и для Vue..

Еще одна оговорка: эта статья не является надлежащей документацией по обоим фреймворкам, поэтому если вы ищете, как их использовать, то порекомендую вам обратиться к документации по соответствующему фреймворку.

Сходство

Оба являются javascript-фреймворками. Я правильно понимаю?

Шучу! Давайте посмотрим на сходства, присущие обоим фреймворкам, прежде чем выделить особенности, которые являются уникальными для каждого из них.

Виртуальный DOM

Document Object Model (DOM) — это объект, определяющий структуру документа. Проще говоря, то, как вы располагаете все элементы HTML. Чтобы оптимизировать рендеринг DOM при изменениях, обе платформы используют виртуальный DOM, где DOM структурируется прямо перед страницей с изменениями, отображаемыми пользователю, так что пользователю не придется сталкиваться со сбоями.

Изменения событий

Обе технологии полагаются на изменения событий, где состояние играет важную роль. Это запуск таких событий, как установка, рендеринг и обновление (так называемые жизненные циклы). В отличие от традиционного подхода JQuery, где вы должны самостоятельно инициировать событие, React и Vue помогают разработчику все инкапсулировать в событие, таким образом повторный рендеринг может быть запущен при изменении состояния.

На основе компонентов

Возможность создавать компоненты - вот что делает этот фреймворк выбором разработчиков, так как он позволяет сократить много работы благодаря принципу "Не повторяйся" Don't Repeat Yourself (DRY).

React

JSX

Когда вы упоминаете React, всегда вспоминается JSX. Хотя вам кажется, что вы пишете HTML, на самом деле вы используете JSX, где Javascript позже проанализирует его в объекте, а React запустит функцию для преобразования во что-то вроде document.getElementByElement. Вот почему внутри JSX вы должны использовать className вместо class, поскольку слово class зарезервировано в Javascript.

const Component = () => {
  return (
    <div className="wrapper"/>
  );
}

Декларативы

Поскольку мы объединяем все под одной функцией для одного компонента, то проще использовать объявленную переменную.

const Component = () => {
  const name = "John";

  return (
    <p>{name}</p>
  );

Чтобы запустить весь javascript внутри JSX, достаточно раскрыть фигурные скобки, и вы можете делать все, что угодно.

const Component = () => {
  const names = ["John", "Adam", "Mark"];
  const [age, setAge] = useState(12);

  const increaseAge = () => setAge(age++);

  return (
    <div>
      { names.map(name => (<p>{name}</p>) }
      <button onClick={increaseAge}>Increase Age</button>
    </div>
  );
};

Хуки

Не поймите меня неправильно. Vue также имеет свои собственные хуки. Однако React на самом деле отличается своей сильной стороной в реализации хуков (учитывая, что для их использования необходимо использовать функциональный паттерн). До этого React использовал компонент более высокого порядка (HOC), который также может быть реализован как для компонента класса, так и для функционального компонента. Чтобы сделать его более подробным, React вводит хуки, которые впоследствии представляют более многословный паттерн, и разработчик может разделить свой код на основе функциональности, а не жизненного цикла. Самые основные хуки, useState и useEffect, являются наиболее используемыми в экосистеме React.

const Component = () => {
  const [state, setState] = useState();

  useEffect(() => {
    console.log("Hello console!");
  });
};

Состояния и пропсы

Что мне нравится в React, так это то, как вы можете оптимизировать состояние и пропсы. Из useState вы можете оптимизировать его путем мемоизации с помощью useMemo, затем, если вам нужно поднять и сгруппировать несколько состояний, вы можете использовать useReducer. Обратите внимание, что вам также необходимо определить издержки, связанные с использованием хуков.

Чтобы передать пропсы, вы можете просто отправить их вместе с функцией компонента, как показано ниже:

const Component = (props) => {
  // The rest of the component
  <p>{props.name}</p>
};

Когда вы импортируете компонент, вы можете передать ему все, что вам нужно, таким образом:

<Component name="John" />

Допустим, у вас не произошло много изменений с определенным компонентом, мы также можем использовать чистый компонент, поэтому рендеринг будет предсказуем для всех рендеров, и вам не придется помещать useState внутрь него.

Жизненный цикл React

React имеет стандартный жизненный цикл компонента - установка, обновление, удаление. В классе компонента есть методы, которые используются, например componentDidUpdate, componentWillUnmount. В функциональных компонентах все это упаковано в useEffect, где вы можете установить, на какие изменения он будет подписываться, и разделить код на части более оптимально.

const Component = () => {
  useEffect(() => {
    // Functions here are equivalent to
    // `componentDidMount`, `shouldComponentUpdate`
    // and `componentDidUpdate`
    return () => {
      // Functions here are equivalent to
      // `componentWillUnmount`
    };
  }, [changesDeps]); // Changes can be state, props
};

Обратите внимание, что useEffect можно использовать многократно, в отличие от метода жизненного цикла класса, который можно использовать только один раз в одном классе.

Vue

Прежде чем перейти к подробностям о Vue, я буду использовать только метод Vue 3, в основном на Composition API. Для разработчиков React: я лично использую Vue Composition API, который действительно похож на React. Я могу немного коснуться обычного шаблона, просто чтобы сравнить, насколько прост Vue в плане детализации и оптимизации.

Шаблоны

В отличие от React, Vue использует обычный HTML-шаблон, а не JSX. Поэтому Vue рекомендует применение шаблонов (хотя вы также можете воспользоваться функцией рендеринга и JSX, если в этом есть необходимость). Можно задействовать обычный шаблон, включая обычный класс элемента.

<template>
    <div class="wrapper"/>
</template>

Декларативный

Vue имеет свой собственный стиль объявления переменной. Традиционным способом вы можете передать переменную в качестве data при экспорте компонента вместе с шаблонами.

<template>
  <div>
    <p>{{ name }}</p>
  </div>
</template>

<script>
import { defineComponent } from 'vue';

const Component = defineComponent({
  data() {
    return {
      name: "John",
    };
  },
});
</script>

Однако, начиная с Vue 3, где был представлен Composition API, разработчику был предоставлен новый способ написания компонента, в котором разработчик React, такой как я, чувствует себя как дома; он помогает как можно быстрее освоить Vue.

Обратите внимание, что Composition API в Vue 3 не полностью заменил старый паттерн из Vue 2, а просто предоставил более детальный способ написания компонента.

<template>
  <div>
    <p>{{ name }}</p>
  </div>
</template>

<script setup>
const name = "John";
</script>

Проще, верно?

Итак, как насчет рендеринга, включающего условия и циклы? Vue вводит биндинг, когда вы привязываете переменную к содержимому внутри шаблона.

<template>
  <div :class="wrapperClass" v-if="counter < 3">
    <p>{{ name }}</p>
    <button @click="increaseCounter">Increase</button>
  </div>
</template>

<script setup>
import { ref } from "vue";
const name = "John";
const counter = ref(0);
const wrapperClass = "wrapper";
const increaseCounter = () => counter++;
</script>

Состояния и пропсы

Прежде всего, заметим, что у нас есть вещь под названием data? Да, она служит той же цели, что и state в React, где она будет обрабатывать реактивность. Это нужно для того, чтобы убедиться, что состояние неизменяемо. Но в следующем примере я просто покажу аналог script setup.

<template>
  <div>
    <p>{{ counter }}</p>
    <p>{{ user.name }}</p>
  </div>
</template>

<script setup>
import { ref, reactive } from "vue";

const counter = ref(0);
const user = reactive({
  name: "John",
});
</script>

Итак, как насчет пропсов? Хорошо, давайте я покажу вам старый и новый способ.

<template>
  <div>
    <p>{{ counter }}</p>
  </div>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
  props: {
    counter: Number,
  },
});
</script>
<template>
  <div>
    <p>{{ props.counter }}</p>
  </div>
</template>

<script setup>
import { defineProps } from "vue";

const props = defineProps({
  counter: Number,
});
</script>

Таким образом, когда вы импортируете свой компонент в другое место, он ведет себя так же, как React передает пропсы.

<template>
  <Countdown counter="3" />
</template>

<script setup>
import Countdown from "../sources/";
</script>

Жизненные циклы Vue

Поток жизненных циклов между React и Vue в целом одинаков, при этом Vue вносит некоторые дополнения в этот процесс. (Я еще не использовал жизненный цикл достаточно широко, поэтому позже обновлю эту статью, если найду новую информацию).

Итак, старый способ (Option API)

<script>
export default defineComponent({
  mounted() {
    // Execute function after mounted
  },
});
</script>

Способ script setup (Composition API),

<script setup>
onMounted(() => {
  // Execute function after mounted
});
</script>

Здесь вы можете увидеть использование хуков внутри Vue!

Заключение

React и Vue предлагают свой собственный способ управления состояниями и пропсами, жизненными циклами, а также свой способ выполнения функций и привязки их к HTML. Конечно, следующий вопрос должен быть "какой из них лучше?", тем не менее, оба они очень сильно развились и будут совершенствоваться в будущем. Поэтому, повторюсь, моя цель — выделить особенности с обеих сторон, чтобы мы могли самостоятельно понять каждый шаблон. В дальнейшем вы сможете сразу же начать работать с другой стороной, не беспокоясь о повторном обучении.

Что для меня проще? Скажу, что React, но это не дает справедливого сравнения с Vue, учитывая, что я все еще в нем новичок.

Если вы считаете, что в каждом из перечисленных фреймворков не хватает какого-то ключевого момента, пишите в комментариях ниже.


Материал подготовлен в рамках курса «React.js Developer». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.

Комментарии (3)