/ JavaScript

Почему я предпочитаю React, а не Vue

Vue - это JavaScript фреймворк по дефолту поставляемый в Laravel приложениях (до 6 версии). Я, являясь частью сообщества Laravel, часто получаю вопрос, по предпочтению React в противовес Vue. Ввиду этого, я решил написать статью, где расскажу о нескольких примечательных причинах своего выбора.

Ранее я уже писал статьи по React. В прошлой статье я рассказывал, как выучить основы Реакта за 5 минут. А в другой статье я сравнивал титанов JavaScript, где рассказал о личных предпочтениях фреймворка при разработке.

DISCLAIMER!

Vue - отличный фреймворк, на котором я сделал много проектов, и продолжаю с ним работать. Просто, лично я, предпочитаю React в большинстве случаях, где у меня карт-бланш на выбор стека. Этот пост не предназначен для того, чтобы убедить вас использовать React. Я просто хочу поделиться рассуждениями о своём выборе и предпочтениях. Если вы ищете более выразительное сравнение между Vue и React, то этот комментарий на Reddit отлично попадает под ваш запрос.

Перед тем, как я начну, приведу несколько заметок о том, как я использую React:

  • Я, как правило, использую TypeScript.
  • Я практически никогда не использую компоненты класса, только функции.
  • Если мне нужна библиотека управления состоянием, я использую Redux + Immer, хотя, я обычно стараюсь придерживаться локального контекста компонента.
  • Я редко разрабатываю полноценные SPA-приложения. Как правило, я создаю гибридные сервер-клиент приложения в связке с бэкендом на Laravel.

Поехали!

Небольшое API необходимое для создания компонента

React имеет очень небольшое API для создания компонентов. Вещи, которые я регулярно импортирую:

  • Fragment
  • createContext
  • Хуки (useState, useEffect, useContext, …)

И обычно этого вполне достаточно для разработки моих приложений.

С другой стороны, в Vue есть огромное количество опций компонентов, свойств экземпляра и директив шаблонов, которые нужно запомнить. Я предпочитаю скромный набор API React-а. По-сути, vue имеет в себе надстройку над JavaScript, и вам приходится учить новый Vue-синтаксис. В то время, когда React - это чистый JavaScript. Да, продвинутого уровня, но здесь нет никакой магии, только знание JavaScript!

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

То же самое можно сказать и о слотах (slots). В React слотов на самом деле не существует, потому что props уже решает эту проблему.

<template>
  <button @click="$emit('click', $event')">
    <slot />
  </button>
</template>
function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

Функции против классов

Большинство компонентов, которые я пишу, по сути, являются функциями, получающие данные через props и возвращают шаблон. React позволяет использовать функциональные компоненты, поэтому нет синтаксических накладных расходов на использование классов или объектов. Больше никаких рассуждений о ключевом слове this, просто props => view.

function Avatar({ user }) {
  return (
    <img
      src={user.avatarUrl}
      alt={`User ${user.username}'s avatar`}
    />
  );
}

JSX

React использует JSX для шаблонизации представлений, который является надстройкой JavaScript. Наличие шаблонов, встроенных в близкий к JavaScript синтаксис, даёт существенное преимущество: в целом JSX легко использовать в любом JavaScript проекте, так как JSX-файлы могут быть легко перекомпилированы Babel-ом.

Не буду врать, иногда мне не хватает более чистого способа сделать оператор if в моих шаблонах, но в целом, я счастливый пользователь JSX.

Я знаю, что вы можете использовать JSX с Vue, я уже писал об этом, но, в целом, я предпочитаю придерживаться стандартных настроек, поставляемых фреймворком.
Для иллюстрации, вот небольшое сравнение .vue и .jsx:

<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      {{ user.firstName }} {{ user.lastName }}
    </li>
  </ul>
</template>

<script>
export default {
  props: ['users']
}
</script>
function UsersList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          {user.firstName} {user.lastName}
        </li>
      ))}
    </ul>
  );
}

Отсутствие таких директив как v-for и v-if для стандартных операций добавляет к кривой обучения JSX несколько пунктов, однако, я считаю, что в долгосрочной перспективе лучше придерживаться стандартных языковых возможностей.

Fragments

В React компоненты не имеют ограничения на возврат ровно одного элемета DOM. Вы можете вернуть список элементов, или просто текст, обёрнутый в компонент Fragment.

function UserDetails({ user }) {
  return (
    <>
      {user.firstName} {user.lastName}
      <span>{user.age}</span>
    </>
  );
}

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

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

Отличная поддержка TypeScript

Так как React - это просто JavaScript, то и с TypeScript он работает очень хорошо. Типы и интерфейсы работают просто прекрасно.

Рассмотрим компонент вывода элементов списка, переданных через props с функцией renderItem:

type Props = {
  items: T;
  renderItem: (item: T) => React.Node;
}

function GenericList<T>({ items, renderItem }: Props) {
  return (
    <ul>
      <li>
        {items.map((item, i) => (
          <li key={i}>
              {renderItem(item)}
          </li>
        ))}
      </li>
    </ul>
  );
}

Теперь давайте используем этот компонент для вывода списка пользователей:

type User = {
  firstName: string;
  lastName: string;
}

type Props = {
  users: Array<User>;
}

function UsersList({ users }: Props) {
  return (
    <GenericList
      items={users}
      renderItem={user => (
        <>{user.firstName} {user.lastName}</>
      )}
    />
  );
}

Поскольку типы в TypeScript отлично работают c динамическими элементами, то пользовательский параметр в renderItem будет правильно выведен, а user.firstName и user.lastName будут автодополнены в моём редакторе. Ура!

function SignupForm() {
  const [email, setEmail] = useState('');

  // ...
}

Поскольку мы передали строку в качестве дефолтного значения useState, TypeScript знает, что в остальной части компонента email будет строкой и setEmail ожидает строку.

Использование TypeScript с Vue возможно, но нужно писать свои компоненты с чем-то вроде vue-class-component, который по синтаксису намного отличается от стандартных компонентов Vue.

React решает проблемы на фундаментальном уровне

Это самая большая причина, почему я люблю React. React переосмысливает проблемы с первых принципов.

React имеет большой опыт внедрения низкоуровневых "примитивов" для решения проблем высокого уровня. Ярким примером этого является добавление хуков (когда-то давным-давно).

Заключительные мысли

То, как React обрабатывает шаблоны, или то, как props и состояние объявляются в сравнении с тем, как Vue делает эти вещи, является поверхностным. Я предпочитаю "синтаксис" React, который не повлияет на то, как я создаю приложения.

По мере эволюции React за последний год или два, я заметил несколько основных идей:

  • API остается простым и декларативным с сильным акцентом на композиционность.
  • Команда React обычно переосмысливает вещи снизу вверх.

Вот почему я люблю React.

В этой статье я описал о личных предпочтениях, почему стоит выбирать React, и какие у него преимущества. Я описал об отличиях React от Vue, которые заметил на собственном опыте. Но, в любом случае, я бы советовал изучить оба фреймворка, и использовать в правильном контексте ^^.