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

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

Vue или React?
Для проведения эксперимента я решил создать пару довольно стандартных To-Do-приложений, которые позволяют пользователю добавлять элементы в список дел и удалять их из него. Оба приложения разработаны с использованием стандартных CLI (
create-react-app
для React и vue-cli
для Vue). CLI — это, если кто не знает, сокращение, которое расшифровывается как Command Line Interface, то есть — интерфейс командной строки.Теперь предлагаю взглянуть на внешний вид приложений, о которых идёт здесь речь.

Приложения, созданные средствами Vue и React
Вот репозитории с кодом этих приложений: Vue ToDo, React ToDo.
И там и там используется абсолютно одинаковый CSS-код, единственная разница заключается в том, где именно размещены соответствующие файлы. Учитывая это, давайте взглянем на структуру проектов.

Структура проектов, использующих Vue и React
Как можно заметить, структура этих двух проектов практически идентична. Единственное серьёзное различие заключается в том, что у React-приложения имеется три CSS-файла, в то время как у Vue-приложения их нет совсем. Причина подобного заключается в том, что, при использовании
create-react-app
, компоненты React оснащаются сопутствующими им CSS-файлами, а CLI Vue использует другой подход, когда стили объявляются внутри конкретного файла компонента.В итоге и тот и другой подход позволяют достичь одной и той же цели, при этом, при желании, ничто не мешает организовать стили иначе, что в Vue, что в React. На самом деле, тут всё сводится к личным предпочтениям того, кто создаёт веб-проект. Например, тема структурирования CSS постоянно обсуждается в сообществах разработчиков. Сейчас мы просто будем следовать стандартным подходам к работе с CSS, заложенным в CLI рассматриваемых фреймворков.
Однако прежде чем мы пойдём дальше, давайте взглянем на то, как выглядит типичный компонент Vue и React.
Вот код компонента Vue (в нашем проекте он находится в файле
ToDoItem.vue
).<template>
<div class="ToDoItem">
<p class="ToDoItem-Text">{{todo.text}}</p>
<div class="ToDoItem-Delete"
@click="deleteItem(todo)">-
</div>
</div>
</template>
<script>
export default {
name: "to-do-item",
props: ['todo'],
methods: {
deleteItem(todo) {
this.$emit('delete', todo)
}
}
}
</script>
<style>
.ToDoItem {
display: flex;
justify-content: center;
align-items: center;
}
.ToDoItem-Text {
width: 90%;
background-color: white;
border: 1px solid lightgrey;
box-shadow: 1px 1px 1px lightgrey;
padding: 12px;
margin-right: 10px;
}
.ToDoItem-Delete {
width: 20px;
padding: 5px;
height: 20px;
cursor: pointer;
background: #ff7373;
border-radius: 10px;
box-shadow: 1px 1px 1px #c70202;
color: white;
font-size: 18px;
margin-right: 5px;
}
.ToDoItem-Delete:hover {
box-shadow: none;
margin-top: 1px;
margin-left: 1px;
}
</style>
Вот код React-компонента (файл
ToDoItem.js
).import React, {Component} from 'react';
import './ToDoItem.css';
class ToDoItem extends Component {
render() {
return (
<div className="ToDoItem">
<p className="ToDoItem-Text">{this.props.item}</p>
<div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div>
</div>
);
}
}
export default ToDoItem;
Теперь пришло время погрузиться в детали.
Как выполняется изменение данных?
Изменение данных ещё называют «мутацией данных». Речь идёт об изменениях, вносимых в данные, которые хранит наше приложение. Так, если нам нужно изменить имя некоего человека с «Джон» на «Марк», то речь идёт о «мутации данных». Именно в подходе к изменению данных и находится ключевое различие между React и Vue. А именно, Vue создаёт объект
data
, в котором находятся данные, и содержимое которого можно свободно менять. React же создаёт объект state
, в котором хранится состояние приложения, и при работе с которым для изменения данных требуются некоторые дополнительные усилия. Однако в React всё устроено именно так не без причины, ниже мы об этом поговорим, а для начала рассмотрим вышеупомянутые объекты.Вот как выглядит объект
data
, который используется в Vue.data() {
return {
list: [
{
todo: 'clean the house'
},
{
todo: 'buy milk'
}
],
}
},
Вот как выглядит объект
state
, применяемый в React:constructor(props) {
super(props);
this.state = {
list: [
{
'todo': 'clean the house'
},
{
'todo': 'buy milk'
}
],
};
};
Как видите, в обоих случаях мы описываем одни и те же данные, они просто по-разному оформлены. В результате можно сказать, что передача изначальных данных компонентам в Vue и React выглядит очень и очень похоже. Но, как уже было сказано, подходы к изменению существующих данных в этих фреймворках различаются.
Предположим, у нас имеется элемент данных вроде
name: ‘Sunil’
. Тут я присвоил свойству name
моё собственное имя.В Vue обратиться к этим данным можно с помощью конструкции
this.name
. А вот как их поменять: this.name = ‘John’
. Не знаю точно, как бы я себя чувствовал, если бы моё имя и правда изменилось, но в Vue это работает именно так.В React же обратиться к тем же данным можно с помощью конструкции
this.state.name
. А вот поменять их, написав нечто вроде this.state.name = ‘John’
, нельзя, так как в React действуют ограничения, предотвращающие подобные изменения данных. Поэтому в React приходится пользоваться чем-то наподобие this.setState({name: ‘John’})
.Результатом подобной операции является то же самое, что получается после выполнения более простой операции в Vue. В React приходится писать больше кода, но в Vue существует что-то вроде особой версии функции
setState
, которая вызывается при, как кажется, простом изменении данных. Поэтому, если подвести итоги, React требует использования команды setState
с передачей ей описания данных, которые надо изменить, а Vue работает, исходя из предположения, что разработчик хотел бы воспользоваться чем-то подобным, меняя данные внутри объекта data
.Теперь зададимся вопросами о том, почему в React всё устроено именно так, и зачем вообще нужна функция
setState
. Ответы на эти вопросы можно узнать у Реванта Кумара: «Это так потому что React стремится повторно выполнить, при изменении состояния, определённые хуки жизненного цикла, такие, как componentWillReceiveProps
, shouldComponentUpdate
, componentWillUpdate
, render
, componentDidUpdate
. Он узнаёт о том, что состояние изменилось, когда вы вызываете функцию setState
. Если бы вы меняли состояние напрямую, React пришлось бы выполнять гораздо больше работы для отслеживания изменений, для определения того, какие хуки жизненного цикла надо запускать, и так далее. В результате React, для того, чтобы облегчить себе жизнь, использует setState
».Теперь, когда с изменениями данных мы разобрались, поговорим о том, как, в обеих версиях нашего приложения, добавлять новые элементы в список дел.
Добавление новых элементов в список дел
?React
Вот как это делается в React.
createNewToDoItem = () => {
this.setState( ({ list, todo }) => ({
list: [
...list,
{
todo
}
],
todo: ''
})
);
};
Здесь у поля служащего для ввода данных (
input
), имеется атрибут value
. Этот атрибут обновляется автоматически благодаря использованию пары взаимосвязанных функций, которые формируют то, что называется двусторонней привязкой данных (если вы о таком раньше не слышали — подождите немного, мы поговорим об этом в разделе, посвящённом добавлению элементов в Vue-приложении). Эту разновидность двусторонней связи мы создаём благодаря наличию дополнительного прослушивателя событий onChange
, прикреплённому к полю input
. Взглянем на код этого поля для того, чтобы вам было понятнее то, что здесь происходит.<input type="text"
value={this.state.todo}
onChange={this.handleInput}/>
Функция
handleInput
вызывается при изменении значения поля input
. Это приводит к обновлению элемента todo
, который находится внутри объекта state
, путём установки его в то значение, которое имеется в поле input
. Вот как выглядит функция handleInput
.handleInput = e => {
this.setState({
todo: e.target.value
});
};
Теперь, когда пользователь нажимает на странице приложения кнопку
+
для добавления в список новой записи, функция createNewToDoItem
вызывает метод this.setState
и передаёт ему функцию. Эта функция принимает два параметра. Первый — это весь массив list
из объекта state
, а второй — это элемент todo
, обновляемый функцией handleInput
. Затем функция возвращает новый объект, который содержит прежний массив list
, и добавляет новый элемент todo
в конец этого массива. Работа со списком организована с использованием оператора spread
(если вы с ним раньше не встречались — знайте, что это одна из новых возможностей ES6, и поищите подробности о нём).И наконец, в
todo
записывается пустая строка, что автоматически обновляет значение value
в поле input
.?Vue
Для добавления нового элемента в список дел в Vue используется следующая конструкция.
createNewToDoItem() {
this.list.push(
{
'todo': this.todo
}
);
this.todo = '';
}
В Vue у поля ввода имеется директива
v-model
. Она позволяет организовать двустороннюю привязку данных. Взглянем на код этого поля и поговорим о том, что тут происходит.<input type="text" v-model="todo"/>
Директива
v-model
привязывает поле к ключу, который имеется в объекте данных, который называется toDoItem
. Когда страница загружается, в toDoItem
записана пустая строка, выглядит это как todo: ‘’
.Если тут уже имеются какие-то данные, нечто вроде
todo: ‘add some text here’
, то в поле ввода попадёт такой же текст, то есть — ‘add some text here’
. В любом случае, если вернуться к примеру с пустой строкой, текст, который мы введём в поле, попадёт, за счёт привязки данных, в свойство todo
. Это и есть двусторонняя привязка данных, то есть, ввод новых данных в поле приводит к записи этих данных в объект data
, а обновление данных в объекте приводит к появлению этих данных в поле.Теперь вспомним функцию
createNewToDoItem()
, о которой мы говорили выше. Как можно видеть, мы помещаем содержимое todo
в массив list
, а затем записываем в todo
пустую строку.Удаление элементов из списка
?React
В React эта операция выполняется так.
deleteItem = indexToDelete => {
this.setState(({ list }) => ({
list: list.filter((toDo, index) => index !== indexToDelete)
}));
};
В то время как функция
deleteItem
находится в файле ToDo.js
, обратиться к ней без проблем можно и из ToDoItem.js
, сначала передав эту функцию как свойство в <ToDoItem/>
. Вот как это выглядит:<ToDoItem deleteItem={this.deleteItem.bind(this, key)}/>
Тут мы сначала передаём функцию, что делает её доступной дочерним компонентам. Кроме того, мы осуществляем привязку
this
и передачу параметра key
. Этот параметр используется функцией для того, чтобы отличить элемент ToDoItem
, который нужно удалить, от других элементов. Затем, внутри компонента ToDoItem
, мы делаем следующее.<div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div>
Всё, что нужно сделать для того, чтобы обратиться к функции, находящейся в родительском компоненте — это воспользоваться конструкцией
this.props.deleteItem
.?Vue
Удаление элемента списка в Vue выполняется так.
onDeleteItem(todo){
this.list = this.list.filter(item => item !== todo);
}
В Vue требуется несколько иной подход к удалению элементов, чем тот, которым мы пользовались в React. А именно, тут надо выполнить три действия.
Во-первых, вот что надо сделать в элементе, для которого нужно будет вызвать функцию его удаления.
<div class="ToDoItem-Delete" @click="deleteItem(todo)">-</div>
Затем нужно создать функцию
emit
в виде метода в дочернем компоненте (в данном случае — в ToDoItem.vue
), которая выглядит следующим образом.deleteItem(todo) {
this.$emit('delete', todo)
}
Далее, вы можете заметить, что мы, добавляя
ToDoItem.vue
внутри ToDo.vue
, обращаемся к функции.<ToDoItem v-for="todo in list"
:todo="todo"
@delete="onDeleteItem" // <-- this :)
:key="todo.id" />
Это — то, что называется пользовательским прослушивателем событий. Он реагирует на вызовы
emit
со строкой delete
. Если он фиксирует подобное событие, он вызывает функцию onDeleteItem
. Она находится внутри ToDo.vue
, а не в ToDoItem.vue
. Эта функция, как уже сказано выше, просто фильтрует массив todo
, находящийся в объекте data
для того, чтобы удалить из него элемент, по которому щёлкнули.Кроме того, стоит отметить, что в примере с использованием Vue можно было бы просто написать код, относящийся к функции
emit
, внутри прослушивателя @click
. Выглядеть это может так.<div class="ToDoItem-Delete" @click="$emit(‘delete’, todo)">-</div>
Это уменьшило бы число шагов, необходимых для удаления элемента списка, с трёх до двух. Как именно поступить — вопрос предпочтений разработчика.
Если подвести краткие итоги этого раздела, то можно сказать, что в React доступ к функциям, описанным в родительских компонентах, организуется через
this.props
(учитывая то, что props
передаётся дочерним компонентам, что является стандартным приёмом, который можно встретить буквально повсюду). В Vue же дочерние компоненты должны вызывать события с помощью функции emit
, а эти события уже обрабатываются родительским компонентом.Работа с прослушивателями событий
?React
В React прослушиватели событий для чего-то простого, вроде события щелчка, весьма просты. Вот пример создания обработчика события
click
для кнопки, создающей новый элемент списка дел.<div className="ToDo-Add" onClick={this.createNewToDoItem}>+</div>
Тут всё устроено весьма просто, это очень похоже на обработку подобных событий с использованием чистого JavaScript.
Надо отметить, что здесь настройка прослушивателей событий нажатий на кнопки клавиатуры, например, на
Enter
, занимает немного больше времени, чем в Vue. Тут нужно, чтобы событие onKeyPress
обрабатывалось бы следующим образом. Вот код поля ввода.<input type="text" onKeyPress={this.handleKeyPress}/>
Функция
handleKeyPress
вызывает функцию createNewToDoItem
, когда распознаёт нажатие на Enter
. Выглядит это так.handleKeyPress = (e) => {
if (e.key === ‘Enter’) {
this.createNewToDoItem();
}
};
?Vue
Обработчики событий в Vue настраивать весьма просто. Тут достаточно использовать символ
@
, а затем указать тип прослушивателя, который мы хотим использовать.Например, для добавления прослушивателя события щелчка можно использовать следующий код.
<div class="ToDo-Add" @click="createNewToDoItem()">+</div>
Обратите внимание на то, что
@click
— это сокращение от v-on:click
. Прослушиватели событий Vue хороши тем, что ими можно весьма тонко управлять. Например, если присоединить к прослушивателю конструкцию .once
, это приведёт к тому, что прослушиватель сработает лишь один раз.Существует и множество сокращений, упрощающих написание прослушивателей, реагирующих на нажатия клавиш на клавиатуре. В React, как мы уже говорили, это занимает больше времени, чем в Vue. Здесь же это делается очень просто.
<input type="text" v-on:keyup.enter="createNewToDoItem"/>
Передача данных дочерним компонентам
?React
В React свойства передаются дочернему компоненту при его создании. Например, так:
<ToDoItem key={key} item={todo} />
Здесь можно видеть два свойства, переданных компоненту
ToDoItem
. С этого момента к ним можно обращаться в дочернем компоненте через this.props
.Например, для того, чтобы обратиться к свойству
item.todo
, достаточно использовать конструкцию this.props.item
.?Vue
В Vue свойства дочерним компонентам также передаются при их создании.
<ToDoItem v-for="todo in list"
:todo="todo"
:key="todo.id"
@delete="onDeleteItem" />
После этого они передаются в массив
props
дочернего компонента, например, с помощью конструкции props: [ ‘todo’ ]
. Обращаться к этим свойствам в дочерних компонентах можно по имени, в нашем случае это имя ‘todo’
.Передача данных родительскому компоненту
?React
В React сначала дочернему компоненту передаётся функция, как свойство, там, где вызывается дочерний компонент. Затем выполняется планирование вызова этой функции, например, путём добавления её в качестве обработчика
onClick
, или её вызов, путём обращения к this.props.whateverTheFunctionIsCalled
. Это приводит к вызову функции, находящейся в родительском компоненте. Именно этот процесс описан в разделе об удалении элементов из списка.?Vue
При использовании Vue, в дочернем компоненте достаточно написать функцию, которая передаёт данные родительской функции. В родительском компоненте пишется функция, которая прослушивает события передачи значения. При возникновении подобного события такая функция вызывается. Как и в случае с React, описание этого процесса можно найти в разделе об удалении элементов из списка.
Итоги
Мы поговорили о том, как добавлять, удалять и изменять данные в приложениях, основанных на Vue и React, о том, как передавать данные, в виде свойств, от родительских компонентов дочерним, и как отправлять данные от дочерних компонентов родительским. Полагаем, что после анализа примеров сходства и различия Vue и React видны, что называется, невооружённым глазом.
Существует, конечно, множество других небольших различий между React и Vue, но хочется надеяться, что то, что мы рассмотрели здесь, послужит хорошей основой для понимания того, как работают эти фреймворки. Фреймворки часто анализируют при выборе подходящей платформы для нового проекта. Надеемся, этот материал поможет такой выбор сделать.
Уважаемые читатели! Какие различия между React и Vue, на ваш взгляд, являются самыми главными, влияющими на выбор того или иного фреймворка, например, в качестве основы для некоего проекта?

Комментарии (61)
anfield343
07.08.2018 12:06Пусть меня заминусуют, но все же скажу. Сами по себе react и vue норм штуки, на обоих лично мне достаточно удобно писать. Но как только проект разрастается все больше и больше, и к реакту нужно подключать react-redux… Одно дело просто создать store, actionCreators, reducers, но если нужно идти дальше и создавать 100500 middlewars, selectors, получается такая лапша из всей этой писанины, что хочется застрелиться, и ладно если это все самому писать, но разбирать чей-то другой код и без документации без комментов — это дичь. Возможно я ошибаюсь, но ради фронта создавать такую лапшу — это не очень объективно. ИМХО.
xakepmega
07.08.2018 12:43ну если писать фронт на ваниле или жикверях то цикломатичность взлетит до небес намного раньше
de1m
07.08.2018 13:31+1Что делать то?
gnaeus
07.08.2018 16:26MobX + React Context API? Для очень сложных вещей MobX State Tree
de1m
07.08.2018 16:38а для vue?
gnaeus
07.08.2018 16:54А Vue и так уже работает как React + MobX :)
А вот как управлять в Vue сложными реляционными данными (по типу MobX State Tree) я и сам не знаю.
Вообще, у Реакта самые продвинутые средства управления состоянием. Потому что он, в отличие от других фреймворков, не лезет в это сам, а предоставляет эту роль сторонним библиотекам.anfield343
07.08.2018 17:44для Vue есть VueX. Но его нужно использовать если точно знаешь что он нужен.
gnaeus
07.08.2018 18:00А он умеет работать с нормализованными реляционными данными?
Вот пример с MST. Изнутри хранилище выглядит так:
{ authors: { 123: { id: 123, name: "John Doe", books: [4567] } }, books: { 4567: { id: 4567, title: "VueX vs MobX", author: 123 } } }
И инициализировать мы его можем выхлопом Normalizr. А потребителю данных они уже предоставляются в объектном виде (ссылки и массивы Id преобразуются в
computed
поля):
type Author = { id: number; name: string; books: Book[] }; type Book = { id: number; title: string; author: Author };
Причем, поддерживается Reference Integrity:
store.authors[123].books[0] === store.books[4567].author
GIum
07.08.2018 13:49+1Я был вынужден отказаться от redux из-за этого. Попробуйте mobx, в нем нету описанных вам проблем, есть action, есть store, первое умеет менять второе, все! Остальное библиотека сделает сама. такое решение гораздо лучше масштабируется на больших приложениях.
AxisPod
07.08.2018 14:41Очередная тупая статья по сравнению… с пальцем. Vue — фреймворк, React — библиотека, этого достаточно понять, что не стоит сравнивать.
Tangeman
07.08.2018 15:34Самое главное различие — код на React выглядит как код, в котором используются строки для вывода — пусть и с более удобным синтакисом (что на самом деле очень круто — но это единственное что круто). Такой подход затрудняет перевод и изменения дизайна или структуры фронтенда тем кто не является девелопером. Да, есть трюки которые облегчают такие задачи, но это всё же трюки, а не решение.
В случае Vue, можно полностью отделить мух от котлет и не думать о коде, т.е. условно можно легко разделить дизайн и код, в то время как написание на React мало отличается от написания на чём угодно другом (от бейсика до C#), со всеми вытекающими отсюда последствиями (в основном негативными).
PS: Можно много спорить о «правильности» подходов, но всё же более удобно и логично разделять код и данные. Возможно, кому-то без разницы, но иногда стоит думать о том что изменения придётся вносить кому-то другому, и ему может быть не всё равно.staticlab
07.08.2018 17:46Для перевода всё-таки есть специальные средства, и строки, подлежащие переводу, выносятся в отдельные файлы.
vanxant
07.08.2018 19:57… что является мартышкиным трудом.
Потому что у кого-то слова сильно длиннее, чем в default language, у кого-то падежей больше одного, а некоторые вообще задом наперёд пишут. И правкой строк это не решается никак.staticlab
07.08.2018 20:03То есть десктопные, мобильные, игровые и веб-разработчики уже больше 30 лет ошибаются, когда так делают?
vanxant
07.08.2018 20:30-2А вам нравятся надписи типа «в корзине 2 товар(ов) на сумму Руб 1,234»? Пользователям, которые умеют в русский язык — нет, не нравятся. Настолько, что процентов 20 плюются и уходят с такого сайта.
Или вот в той же цивилизации 6, постоянно надписи типа «по приглашению ацтекск. правительства...». Ну не положено словам склоняться, по мнению разработчиков, так что покупатели их игрулек должны страдать. Хотя здесь ещё переводчики попытались хоть как-то уложиться в требования языка.
Китайцы, которые vue делали, очевидно хорошо знакомы с проблемой. И поэтому всё сразу сделали правильно.staticlab
07.08.2018 20:52+2Давным давно во всех основных системах интернационализации поддерживаются plural forms. Переводчик, зная особенности языка, сам может корректно описать все варианты в том же файле перевода.
Вы предлагаете на каждый язык делать копию всех компонентов с текстами и переводить их там? Не думаю, что переводчики и верстальщики обрадуются такой "инновации".
Те примеры, что вы приводите, лишь подчёркивают непрофессионализм разработчиков.
faiwer
07.08.2018 21:07Всё не так просто. Даже расположение элементов на форме может отличаться в зависимости от языка. Вот для примера. На русском языке:
от [ввод-даты] до [ввод-даты]
. А на казахском:[ввод-даты] бастап [ввод-даты] бойынша
. Полагаю, это ещё цветочки. Я думаю, что в реально сложных случаях может потребоваться треть формы перекроить.vanxant
07.08.2018 21:40+1Да там куча ситуаций.
В немецком, например, бывают просто очень длинные слова. 40, 60 символов. Которые никак не лезут в отведённое им место и нормально не переносятся. Даже уменьшение шрифта не поможет, нужно перепиливать форму.
В иврите не только обратный порядок букв, там обратный порядок всего. Т.е. кнопки нужно двигать влево и т.д.
В восточно-азиатских языках (с иероглифами) другие виды списков, не такие, как у европейцев. См. тег <ruby>. Да там всё другое, те же даты записывают как-то так: 2018?8?7?.
Во франции за коверканье языка штрафуют, и больно.
В ближневосточных языках не 2 набора букв (прописные/строчные), а 4, и за неверный выбор набора можно неиллюзорно огрести от имама.
Да куча всего.staticlab
07.08.2018 21:50Для форматирования дат есть отдельные механизмы и библиотеки, в том числе браузерный Intl.
staticlab
07.08.2018 22:11В немецком, например, бывают просто очень длинные слова. 40, 60 символов. Которые никак не лезут в отведённое им место и нормально не переносятся. Даже уменьшение шрифта не поможет, нужно перепиливать форму.
Далеко не всегда это требуется. Если дизайн и вёрстка заранее расчитаны под многоязычность, то с этим проблем нет. Как пример: booking.com, который нормально смотрится и с китайским, и с немецким.
В иврите не только обратный порядок букв, там обратный порядок всего. Т.е. кнопки нужно двигать влево и т.д.
Чаще всего это означает дополнительный класс rtl в body, а всё остальное переворачивается стилями. С этим проблем нет.
В восточно-азиатских языках (с иероглифами) другие виды списков, не такие, как у европейцев. См. тег
<ruby>
. Да там всё другое, те же даты записывают как-то так: 2018?8?7?.Как я уже писал, это решается правильными библиотеками интернационализации, а не наколеночным склеиванием дня, месяца и года.
Во франции за коверканье языка штрафуют, и больно.
И правильно делают. А у нас бы взвыли, что притесняют свободу.
В ближневосточных языках не 2 набора букв (прописные/строчные), а 4, и за неверный выбор набора можно неиллюзорно огрести от имама.
А это, кстати, делается автоматически на уровне системного рендеринга шрифтов, т.е. это забота ОС и браузера.
vanxant
07.08.2018 21:31+1Я не предлагаю, я просто рассказываю, как это сделано в нормальных проектах.
То, что миллионы быдлокодеров за фикс прайс с апворка делают иначе — не показатель.
То, что так делают прыщавые стартаперы из долины, которым нужно быстро выкатить MVP для внутреннего рынка — не показатель. А потом им видите ли лень рефакторить своё уг, пусть эти аборигены жрут что дают.
И да, plural forms решают проблему примерно никак.
И да, переводчикам отдаётся только html-код (часть template в листинге в статье), но при желании они могут дописать кусок style. И они отлично умеют с этим работать.staticlab
07.08.2018 21:33То есть все идиоты, одни мы умные? Лихо же вы всех назвали быдлокодерами. Сколько же вы таких "нормальных" проектов назвать можете?
vanxant
07.08.2018 21:44+1Ну как минимум это нормально сделано в vue, а до него в knockout.js. И автоматом во всех приложениях на них. Да блин, даже в Битриксе это реализовано нормально — там на каждый язык заводится отдельный «сайт» с отдельным шаблоном.
Если про игры говорить, то вот Ведьмак, например, сделан правильно. Линейка (ла2) и вообще игры ncsoft тоже. В-общем, всё, что сделано не американцами, как правило, таких проблем не имеет.staticlab
07.08.2018 21:52Так всё-таки как же во Vue отделить мух от котлет и сделать интернационализированную корзину?
Битрикс же сам по себе пример плохого дизайна системы. И я сомневаюсь, что подобная схема интернационализации в нём однажды не вылезет косяками в виде корявой локали в одном из компонентов или расхождения версий при редизайне.
И да, какая же всё-таки схема с переводами использована в Линейке и Ведьмаке?
vanxant
07.08.2018 22:49Так всё-таки как же во Vue отделить мух от котлет и сделать интернационализированную корзину?
Да делайте как хотите. У вас на каждый язык — свой фрагмент html. Внутри вы можете дёргать любые функции (стандартные или свои), использовать условные и тернарные операторы, лепить нужные стили — всё, что вам угодно. И вся эта логика представления инкапсулирована в отдельном файле, никак не зависит от логики компонента и не мешает ни обновлению компонента, ни обновлению других языковых шаблонов.
Битрикс же сам по себе пример плохого дизайна системы.
Ну, конкретно в этом месте у них отличный дизайн. И да, они поддерживают «из коробки» 17, что-ли, языков — как в стандартных шаблонах, так и в админке. И вы ни на одном языке не увидите «2 товар(ов)». Ну, если внедряльщики не постараются.staticlab
07.08.2018 23:16+1Да делайте как хотите. У вас на каждый язык — свой фрагмент html. Внутри вы можете дёргать любые функции (стандартные или свои), использовать условные и тернарные операторы, лепить нужные стили — всё, что вам угодно.
То есть вы предлагаете дёргать функции, условные и тернарные операторы непосредственно переводчику? И что делать, если на одной из страничек произошло какое-то изменение в структуре? Разработчик должен будет пройти по всем шаблонам и внести изменения? А там на каждой странице переводчик всё по-своему сделал. Или нам нужен переводчик-разработчик под каждую языковую версию?
Ну, конкретно в этом месте у них отличный дизайн. И да, они поддерживают «из коробки» 17, что-ли, языков — как в стандартных шаблонах, так и в админке. И вы ни на одном языке не увидите «2 товар(ов)». Ну, если внедряльщики не постараются.
Так в том и дело, что их поддержка языков в своих шаблонах и админках не имеет никакого отношения к контенту, который будет выводить разработчик. И как я понимаю, по крайней мере в 2014 году даже стандартной документированной функции для плюрализации в Битриксе не было, и разработчики делали такие вот костыли: https://dev.1c-bitrix.ru/community/webdev/user/157326/blog/10138/?commentId=54191 Несложно понять, что никакой реальной многоязычной поддержкой и не пахнет.
vanxant
07.08.2018 23:29Да, если вы делаете локализованную версию нормального продукта и хотите её поддерживать, то вам в любом случае придётся держать в штате/на подхвате переводчиков. Потому как тексты меняются, появляются новые фичи, которые тоже нужно переводить и т.д.
И не надо считать технических переводчиков идиотами, как правило это инженеры, получившие второе образование (или типа того), а не просто какие-то там девочки «с филфака и в декрет». Разобраться чисто в html вёрстке и паре несложных функций они вполне могут. Ну, если мы про нормальный продукт говорим, а не про херак-херак и в продакшн, пусть пипл хавает.staticlab
07.08.2018 23:34В вашем варианте я вижу как минимум проблемы с версионированием и констистентностью перевода. Ну разумеется, если всё-таки разработчики не поленились вынести все текстовые строки в языковую базу.
staticlab
07.08.2018 23:43Разобраться чисто в html вёрстке и паре несложных функций они вполне могут.
Справедливости ради, точно так же они могут поддерживать и React, и Angular, и Vue, и любые другие шаблоны.
vanxant
08.08.2018 01:59-1Справедливости ради, в том же реакте код очень быстро скатывается в уг, где всё перемешано. Строки приходят из каких-то непонятных сторонних компонентов вместе с кусками вёрстки, классами и стилями. Очень быстро становится сложно выяснить, где вообще эта строка формируется, и совсем сложно — перевести её так, чтобы при следующем пулле она не обновилась.
staticlab
08.08.2018 09:38+1Я бы так не сказал. Не сложнее, чем в других фреймворках. Всё зависит от качества кода.
vanxant
07.08.2018 22:51И да, какая же всё-таки схема с переводами использована в Линейке и Ведьмаке?
Вы таки не поверите, но там внутре все диалоги, формы и т.д. — это фрагменты html. Просто у каждого варианта, например, в диалоге прибит гвоздями уникальный id.staticlab
07.08.2018 23:50Для диалогов и форм можно поверить, но ещё остаются разного рода сообщения и названия предметов. Думается, что там всё-таки должна быть какая-то языковая база, особенно в Линейке.
vanxant
08.08.2018 01:57А никто не говорил, что оно не в базе хранится:) Разумеется, не в отдельных файлах на каждый предмет. Но — вместе с html тегами. Ну т.е. сама игра ожидает, что там фрагмент html, plain text это частный «нулевой» случай html.
faiwer
07.08.2018 21:59Да да. Вспомнить только сколько было и есть багов, связанных с раскладками клавиатуры и горячими клавишами. И ведь именитые конторы и продукты! Я лично сталкивался с подобными проблемами от Adobe. И ладно бы горячие клавиши просто не работали, но блин были даже проблемы, когда что-то не работало если в имени профиля пользователя есть кириллица! Adobe! Ну как так? :) А QT4? А SublimeText? Да тысячи этих "кривых" приложений.
ПО написанное в чисто англоязычной компании с большой степенью вероятности огребает от всех возможных костылей связанных с локализацией, раскладками, RTL, fonts, etc.
staticlab
07.08.2018 22:16Да, насчёт Adobe соглашусь, у них локализации очень кривые.
И ладно бы горячие клавиши просто не работали, но блин были даже проблемы, когда что-то не работало если в имени профиля пользователя есть кириллица!
Ой, а сколько было примеров глюков ПО, когда в профиле был пробел.
ПО написанное в чисто англоязычной компании с большой степенью вероятности огребает от всех возможных костылей связанных с локализацией, раскладками, RTL, fonts, etc.
Тем не менее, та же Windows всё-таки поддерживают всё многообразие языков, а значит, если делать строго по гайдлайнам, большинства этих проблем удастся избежать. Всё это от халтурности разработки и недостатка тестирования.
faiwer
07.08.2018 22:21Тем не менее, та же Windows всё-таки поддерживают всё многообразие языков, а значит, если делать строго по гайдлайнам, большинства этих проблем удастся избежать.
Полагаю, что MS наступила на большую часть из этих граблей за свою долгую и богатую жизнь.
staticlab
07.08.2018 22:39+1Так ведь в том-то и дело! Моя позиция в том, что уже до нас кто-то неоднократно наступил на грабли i18n, и уже есть готовые решения, которыми лучше пользоваться, чем придумывать свой велосипед. Как раз пример с форматированием дат или денег в тему. Большинство даже русскоязычных разработчиков могут не догадаться, что нельзя просто склеить день, месяц и год.
Тупые же клоны страниц для каждого из языков в общем случае тоже решения не принесут. Цена поддержки такого проекта возрастёт во столько же раз. Если, например, вернуться к вашему примеру с датами "от-до", то может быть и есть смысл отдельной версии формы для казахского языка, но её тоже придётся не забывать поддерживать. Не у всех компаний на это может хватить ресурсов. Тут, как вариант, дизайнер может предложить просто убрать текст, оставив одно только тире (как это сделано, например, на Букинге). Но, разумеется, до варианта "5 товар(ов) в корзине" тоже опускаться не стоит. И, раз уж мы вспомнили про корзину, то языковые версии страниц сами по себе не просклоняют этот текст. Наоборот, если переводчиков оставили наедине с такой страницей, неизбежно появятся коверканья подобного рода. Примеры кустарных переводов в том числе игр это только подтверждают.
mayorovp
08.08.2018 09:12Да, давайте вспомним про игры. Вот, например, Скайрим — игра с хорошей локализацией, перевели даже текстуры. Все как вы любите: отдельная версия всех файлов.
Но постойте! Почему при установке большинства англоязычных модов локализация сбивается и местами пропадает?
Vlad_IT
07.08.2018 22:14+1Перевод понятно. Но сама технология, HTML in JS, это же то, от чего мы так долго уходили в js, так было круто, когда появился Backbone со своими разделяемыми шаблонами, и наконец можно было создавать нормальные приложения на MVC подобной архитектуре. И тут вышел ReactJS, появились новоиспеченные разработчики, которые еще не поняли, почему старики так боятся писать шаблоны в логике.
Самое главное, в C# сообществе давно ругают Windows Forms (пусть грубое сравнение, но это аналогичный компонентный подход), все ругают VCL, и в других языках люди пишут на MVC красотах типа Laravel, Django и.т.д., а мы на фронту кричим какой крутой и модный ReactJS. Понятно, что изоляция компонентов это круто, так можно без проблем создавать ортогональные системы, но реализация в ReactJS очень грубая, куда лучше в Vue с его компонентами на .vue и scoped стилями.
Может я реально старый, но я не испытываю удовольствие от написания/чтения кода на JSX, это какая-та лапша набитая логикой, разметкой и стилями. Vue глоток чистого воздуха, пиши шаблоны на чем хочешь, хочешь на html, хочешь на pug. Можешь разделять шаблоны от логики, а можешь писать прямо в компоненте или юзать JSX.
staticlab
07.08.2018 22:21Кстати забавно, что если поднять холивары Angular.js vs React, то одним из аргументов реактистов было то, что Ангуляр вводит свой язык шаблонов, и его ещё нужно учить дополнительно, а в Реакте можно фигачить компоненты in-place, и это нормально, потому что это "не HTML", а просто другая форма записи вызова функции React.createElement.
Теперь же маятник качается в обратную сторону :)
faiwer
07.08.2018 22:27Всё хуже. Тут недавно товарищ отстаивал позицию, что css-стили написанные через интерполяцию, с анонимными методами и вложенными тернарными операторами, в строках-шаблонах — читаются легче и лучше, чем в SCSS. А каждый топик про несчастный Svelte переполнен хейтерами любого возможного DSL. Дескать даёшь везде встраиваемый JS, пусть даже написанный ногами с нагромождением всех видов кавычек, скобок и хаков вроде
&& ... ||
. Мол JS мы уже знаем. Бррр. Мне не понять. Я даже для тестов часто новый DSL создаю исходя из задачи. А тут шаг в лево, шаг в право, "мой редактор не умеет ваш суржик, закопать!".staticlab
07.08.2018 22:42А тут шаг в лево, шаг в право, "мой редактор не умеет ваш суржик, закопать!".
Интересно, что когда-то их любимый редактор его разработчики всё-таки учили корректно распознавать JSX, Styled-components и т.д. и т.п., да смесь JS и HTML как раз суржик и есть :)
argonavtt
Как же надоело, просто уже воротит от подобного рода статей, докладов, дискуссий. Не проходит и дня, что бы я не увидел как кто то сравнивает очередные front-end фреймворки. Ну серьёзно, вам заняться больше нечем? Неужели в мире front-end ну совсем ничего другого не происходит, что бы заниматься подобным?
FeNUMe
Та ладно, сравнения применения инструментов на реальных задачах почитать интересно. Вот только попадаются они крайне редко. Обычно, как и в этой статье, сравнивают бесполезные
Hello worldTo-Do List.snow28609
вот я точно так же подумал, понятное дело что в самых топовых фреймворках стандартные вещи можно написать быстро и легко, хотелось бы увидеть статью которая показывает ситуации когда один фреймворк намного эфективнее другого, или если таких ситуаций нету, то можно сделать вывод что разницы вообще нету, и дело остается только за личными предпочтениями
gnaeus
А тут наверное дело в том, что все современные фреймворки позволяют писать крупные enterprise-проекты на удовлетворительном уровне. И никто в здравом уме не скажет: «А давайте сейчас все бросим на полпути и начнем переписывать на Vue. Это сейчас модно». А если и скажет, то вряд ли этот проект когда-нибудь увидит свет :)
Поэтому мы и видим статьи вроде: «Мы реализовали крупный проект на React. Все круто» или «Мы реализовали крупный проект на Angular, но есть подводные камни».
И не видим «Мы переписали с Angular на Vue и получили большой профит»
neurocore
Есть такое. Отсюда резонное пожелание: может кто использует перечисленные фреймворки на серьёзных боевых проектах? Хотелось бы узнать их слабые стороны.
vanxant
Да тормоза. Пока у вас две строчки туду — все летает. Как только более-менее сложная аппа с десятками экранов и тысячами объектов, так сразу ой.
ilyaplot
Тормоза обячно появляются, когда неправильно используешь фреймворк или не до конца понимаешь, как он работает.
vanxant
Современные фреймворки затягивают магией. Если, условно, на jquery 80% фронтэнд кода это «собрать данные из модели, положить в шаблон/форму», а затем «собрать данные из инпутов, положить в модель, и не забыть обновить ещё в 100500 местах», то двусторонний бидинг, да еще и с computables, воспринимается просто как чит.
А потом выясняется, что бесплатного сыра таки не бывает, внутрь магии таки надо лезть, и, в общем, применять с осторожностью. Пока разберёшься — уже выйдет какая-нибудь четвёртая версия фреймворка, в которой в очередной раз всё переделали «с нуля» и несовместимо, вместо того, чтобы довести до ума первую.
Odrin
Нет там никакой магии. Есть разрабы, которые не хотят потратить пару дней на изучение доков/статей/исходников. А если разраб не в состоянии разобраться с простейшими вещами — тут проблема не в инструменте.
fukkit
Вот, например, один человек имеет все необходимые кондиции, чтобы разобраться (не на 100%, разумеется) в устройстве современного автомобиля.
Но.
Не имеет абсолютно никакого желания тратить на это своё время, а также учитывать миллион нюансов при каждой поездке.
На мой взгляд современные фронт-энд фреймворки не достигли уровня, когда их можно просто использовать, решая более высокоуровневые задачи.
staticlab
Хотите сказать, что, например, бэкендные фреймворки можно просто использовать, не зная что творится под капотом и не тратя время, чтобы разобраться в этом? Даром, что они на порядок сложнее и объёмнее фронтендных. Однако на собеседованиях соискателей пытают всякими нюансами, не говоря уже об опыте работы.
vanxant
Ну libc вы же используете, скорее всего не зная, что вы вообще его используете.
И да, фронтэнд сложнее. На два порядка.
staticlab
libc хоть и критически важная библиотека, но я говорю про бэкендные веб-фреймворки. И да, занимаясь фронтендом, я знаю, что ведущие бэкендные фреймворки, такие как Spring, значительно сложнее фронтенда. Взять ту же связку react+redux: библиотека для управления DOM с помощью виртуального DOM и простейший конечный автомат. Да, решение это достаточно низкоуровневое. Конкурент из текущей статьи — vue — значительно более высокоуровневый и удобный за счёт обсерверов и втягивающей модели. Но всё это учится довольно быстро, и толковый программист быстро со всем разберётся. Даже бестолковый сумеет быстренько что-нибудь наговнокодить — примеров по всему интернету полно. А вот в бэкенде нужно иметь значительно больше знаний и понимания, что происходит под капотом используемого фреймворка, дабы всё работало эффективно.
Сравнение же с автомобилем всё равно натянутое. Чтобы хорошо управлять автомобилем, всё-таки нужно иметь представление, как он работает. Да, многие автомобили оснащены той же автоматической коробкой, но многие предпочитают механику из-за лучшей динамики. А чтобы управлять механикой, сами понимаете, нужно знать много низкоуровневых нюансов из устройства автомобиля. И ведь тратят на это время, на каждом светофоре выжимая сцепление и переключая передачи...
vanxant
Ну если вы за пару дней разобрались, опишите плз в двух строках, как правильно готовить redux. Ну чтобы там не тормозило и вот это всё.
faiwer
И т.д… В общем нужно добиться того, чтобы render vtree лишний раз не происходил. Чтобы он настигал только те компоненты, которые и правда зависят от тех данных, что были изменены.