Почему я предпочитаю 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, которые заметил на собственном опыте. Но, в любом случае, я бы советовал изучить оба фреймворка, и использовать в правильном контексте ^^.