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

Он почитал документацию, посмотрел несколько учебных видео, и, хотя всё это показалось ему весьма полезным, ему хотелось по-настоящему понять, в чём заключается разница между 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)


  1. argonavtt
    07.08.2018 12:03
    +4

    Как же надоело, просто уже воротит от подобного рода статей, докладов, дискуссий. Не проходит и дня, что бы я не увидел как кто то сравнивает очередные front-end фреймворки. Ну серьёзно, вам заняться больше нечем? Неужели в мире front-end ну совсем ничего другого не происходит, что бы заниматься подобным?


    1. FeNUMe
      07.08.2018 13:59
      +1

      Та ладно, сравнения применения инструментов на реальных задачах почитать интересно. Вот только попадаются они крайне редко. Обычно, как и в этой статье, сравнивают бесполезныеHello worldTo-Do List.


      1. snow28609
        07.08.2018 14:11

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


        1. gnaeus
          07.08.2018 16:24

          А тут наверное дело в том, что все современные фреймворки позволяют писать крупные enterprise-проекты на удовлетворительном уровне. И никто в здравом уме не скажет: «А давайте сейчас все бросим на полпути и начнем переписывать на Vue. Это сейчас модно». А если и скажет, то вряд ли этот проект когда-нибудь увидит свет :)

          Поэтому мы и видим статьи вроде: «Мы реализовали крупный проект на React. Все круто» или «Мы реализовали крупный проект на Angular, но есть подводные камни».
          И не видим «Мы переписали с Angular на Vue и получили большой профит»


    1. neurocore
      07.08.2018 14:23

      Есть такое. Отсюда резонное пожелание: может кто использует перечисленные фреймворки на серьёзных боевых проектах? Хотелось бы узнать их слабые стороны.


      1. vanxant
        07.08.2018 18:27
        -1

        Да тормоза. Пока у вас две строчки туду — все летает. Как только более-менее сложная аппа с десятками экранов и тысячами объектов, так сразу ой.


        1. ilyaplot
          07.08.2018 18:44

          Тормоза обячно появляются, когда неправильно используешь фреймворк или не до конца понимаешь, как он работает.


          1. vanxant
            07.08.2018 19:28

            Современные фреймворки затягивают магией. Если, условно, на jquery 80% фронтэнд кода это «собрать данные из модели, положить в шаблон/форму», а затем «собрать данные из инпутов, положить в модель, и не забыть обновить ещё в 100500 местах», то двусторонний бидинг, да еще и с computables, воспринимается просто как чит.
            А потом выясняется, что бесплатного сыра таки не бывает, внутрь магии таки надо лезть, и, в общем, применять с осторожностью. Пока разберёшься — уже выйдет какая-нибудь четвёртая версия фреймворка, в которой в очередной раз всё переделали «с нуля» и несовместимо, вместо того, чтобы довести до ума первую.


            1. Odrin
              08.08.2018 11:41

              Нет там никакой магии. Есть разрабы, которые не хотят потратить пару дней на изучение доков/статей/исходников. А если разраб не в состоянии разобраться с простейшими вещами — тут проблема не в инструменте.


              1. fukkit
                08.08.2018 12:46

                Вот, например, один человек имеет все необходимые кондиции, чтобы разобраться (не на 100%, разумеется) в устройстве современного автомобиля.
                Но.
                Не имеет абсолютно никакого желания тратить на это своё время, а также учитывать миллион нюансов при каждой поездке.
                На мой взгляд современные фронт-энд фреймворки не достигли уровня, когда их можно просто использовать, решая более высокоуровневые задачи.


                1. staticlab
                  08.08.2018 13:09

                  Хотите сказать, что, например, бэкендные фреймворки можно просто использовать, не зная что творится под капотом и не тратя время, чтобы разобраться в этом? Даром, что они на порядок сложнее и объёмнее фронтендных. Однако на собеседованиях соискателей пытают всякими нюансами, не говоря уже об опыте работы.


                  1. vanxant
                    09.08.2018 00:53

                    Ну libc вы же используете, скорее всего не зная, что вы вообще его используете.
                    И да, фронтэнд сложнее. На два порядка.


                    1. staticlab
                      09.08.2018 01:31

                      libc хоть и критически важная библиотека, но я говорю про бэкендные веб-фреймворки. И да, занимаясь фронтендом, я знаю, что ведущие бэкендные фреймворки, такие как Spring, значительно сложнее фронтенда. Взять ту же связку react+redux: библиотека для управления DOM с помощью виртуального DOM и простейший конечный автомат. Да, решение это достаточно низкоуровневое. Конкурент из текущей статьи — vue — значительно более высокоуровневый и удобный за счёт обсерверов и втягивающей модели. Но всё это учится довольно быстро, и толковый программист быстро со всем разберётся. Даже бестолковый сумеет быстренько что-нибудь наговнокодить — примеров по всему интернету полно. А вот в бэкенде нужно иметь значительно больше знаний и понимания, что происходит под капотом используемого фреймворка, дабы всё работало эффективно.


                      Сравнение же с автомобилем всё равно натянутое. Чтобы хорошо управлять автомобилем, всё-таки нужно иметь представление, как он работает. Да, многие автомобили оснащены той же автоматической коробкой, но многие предпочитают механику из-за лучшей динамики. А чтобы управлять механикой, сами понимаете, нужно знать много низкоуровневых нюансов из устройства автомобиля. И ведь тратят на это время, на каждом светофоре выжимая сцепление и переключая передачи...


              1. vanxant
                10.08.2018 03:02

                Ну если вы за пару дней разобрались, опишите плз в двух строках, как правильно готовить redux. Ну чтобы там не тормозило и вот это всё.


                1. faiwer
                  10.08.2018 07:23

                  • Избегать большого количества connect-ов, т.к. они все вызываются при каждом изменении stor-а. В сложных случаях можно даже свою, какую-нибудь иерархическую версию запилить.
                  • Использовать PureComputed практически повсеместно, опираясь на то, что у нас всё древо данных immutable.
                  • Внимательно следить за тем, что и куда мы передаём в качестве props, чтобы не получалось ситуаций, когда мы каждый раз зазря генерируем новым объект, хотя можно было бы обойтись старым, воспользовавшись мемоизацией.
                  • В целом много-много селекторов и прочих мемоизаторов. Можно даже на основе WeakMap-а.
                  • В целях борьбы с props-hell использовать контекст в ключевых местах.
                  • Профилировать при малейшем подозрении на тормоза. Отслеживать те места, которые подозрительно много считают. Потом "чинить" их, реорганизовывая их потоки данных.

                  И т.д… В общем нужно добиться того, чтобы render vtree лишний раз не происходил. Чтобы он настигал только те компоненты, которые и правда зависят от тех данных, что были изменены.


  1. anfield343
    07.08.2018 12:06

    Пусть меня заминусуют, но все же скажу. Сами по себе react и vue норм штуки, на обоих лично мне достаточно удобно писать. Но как только проект разрастается все больше и больше, и к реакту нужно подключать react-redux… Одно дело просто создать store, actionCreators, reducers, но если нужно идти дальше и создавать 100500 middlewars, selectors, получается такая лапша из всей этой писанины, что хочется застрелиться, и ладно если это все самому писать, но разбирать чей-то другой код и без документации без комментов — это дичь. Возможно я ошибаюсь, но ради фронта создавать такую лапшу — это не очень объективно. ИМХО.


    1. xakepmega
      07.08.2018 12:43

      ну если писать фронт на ваниле или жикверях то цикломатичность взлетит до небес намного раньше


      1. de1m
        07.08.2018 13:31
        +1

        Что делать то?


        1. gnaeus
          07.08.2018 16:26

          MobX + React Context API? Для очень сложных вещей MobX State Tree


          1. de1m
            07.08.2018 16:38

            а для vue?


            1. gnaeus
              07.08.2018 16:54

              А Vue и так уже работает как React + MobX :)

              А вот как управлять в Vue сложными реляционными данными (по типу MobX State Tree) я и сам не знаю.

              Вообще, у Реакта самые продвинутые средства управления состоянием. Потому что он, в отличие от других фреймворков, не лезет в это сам, а предоставляет эту роль сторонним библиотекам.


              1. anfield343
                07.08.2018 17:44

                для Vue есть VueX. Но его нужно использовать если точно знаешь что он нужен.


                1. 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


                  1. anfield343
                    07.08.2018 18:23

                    пока не знаю… увы


    1. GIum
      07.08.2018 13:49
      +1

      Я был вынужден отказаться от redux из-за этого. Попробуйте mobx, в нем нету описанных вам проблем, есть action, есть store, первое умеет менять второе, все! Остальное библиотека сделает сама. такое решение гораздо лучше масштабируется на больших приложениях.


      1. anfield343
        07.08.2018 13:53

        Да. Спасибо. Как раз собирался изучить и сравнить с redux)


  1. AxisPod
    07.08.2018 14:41

    Очередная тупая статья по сравнению… с пальцем. Vue — фреймворк, React — библиотека, этого достаточно понять, что не стоит сравнивать.


  1. Tangeman
    07.08.2018 15:34

    Самое главное различие — код на React выглядит как код, в котором используются строки для вывода — пусть и с более удобным синтакисом (что на самом деле очень круто — но это единственное что круто). Такой подход затрудняет перевод и изменения дизайна или структуры фронтенда тем кто не является девелопером. Да, есть трюки которые облегчают такие задачи, но это всё же трюки, а не решение.

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

    PS: Можно много спорить о «правильности» подходов, но всё же более удобно и логично разделять код и данные. Возможно, кому-то без разницы, но иногда стоит думать о том что изменения придётся вносить кому-то другому, и ему может быть не всё равно.


    1. staticlab
      07.08.2018 17:46

      Для перевода всё-таки есть специальные средства, и строки, подлежащие переводу, выносятся в отдельные файлы.


      1. vanxant
        07.08.2018 19:57

        … что является мартышкиным трудом.
        Потому что у кого-то слова сильно длиннее, чем в default language, у кого-то падежей больше одного, а некоторые вообще задом наперёд пишут. И правкой строк это не решается никак.


        1. staticlab
          07.08.2018 20:03

          То есть десктопные, мобильные, игровые и веб-разработчики уже больше 30 лет ошибаются, когда так делают?


          1. vanxant
            07.08.2018 20:30
            -2

            А вам нравятся надписи типа «в корзине 2 товар(ов) на сумму Руб 1,234»? Пользователям, которые умеют в русский язык — нет, не нравятся. Настолько, что процентов 20 плюются и уходят с такого сайта.
            Или вот в той же цивилизации 6, постоянно надписи типа «по приглашению ацтекск. правительства...». Ну не положено словам склоняться, по мнению разработчиков, так что покупатели их игрулек должны страдать. Хотя здесь ещё переводчики попытались хоть как-то уложиться в требования языка.
            Китайцы, которые vue делали, очевидно хорошо знакомы с проблемой. И поэтому всё сразу сделали правильно.


            1. staticlab
              07.08.2018 20:52
              +2

              Давным давно во всех основных системах интернационализации поддерживаются plural forms. Переводчик, зная особенности языка, сам может корректно описать все варианты в том же файле перевода.


              Вы предлагаете на каждый язык делать копию всех компонентов с текстами и переводить их там? Не думаю, что переводчики и верстальщики обрадуются такой "инновации".


              Те примеры, что вы приводите, лишь подчёркивают непрофессионализм разработчиков.


              1. faiwer
                07.08.2018 21:07

                Всё не так просто. Даже расположение элементов на форме может отличаться в зависимости от языка. Вот для примера. На русском языке: от [ввод-даты] до [ввод-даты]. А на казахском: [ввод-даты] бастап [ввод-даты] бойынша. Полагаю, это ещё цветочки. Я думаю, что в реально сложных случаях может потребоваться треть формы перекроить.


                1. vanxant
                  07.08.2018 21:40
                  +1

                  Да там куча ситуаций.
                  В немецком, например, бывают просто очень длинные слова. 40, 60 символов. Которые никак не лезут в отведённое им место и нормально не переносятся. Даже уменьшение шрифта не поможет, нужно перепиливать форму.
                  В иврите не только обратный порядок букв, там обратный порядок всего. Т.е. кнопки нужно двигать влево и т.д.
                  В восточно-азиатских языках (с иероглифами) другие виды списков, не такие, как у европейцев. См. тег <ruby>. Да там всё другое, те же даты записывают как-то так: 2018?8?7?.
                  Во франции за коверканье языка штрафуют, и больно.
                  В ближневосточных языках не 2 набора букв (прописные/строчные), а 4, и за неверный выбор набора можно неиллюзорно огрести от имама.
                  Да куча всего.


                  1. staticlab
                    07.08.2018 21:50

                    Для форматирования дат есть отдельные механизмы и библиотеки, в том числе браузерный Intl.


                  1. staticlab
                    07.08.2018 22:11

                    В немецком, например, бывают просто очень длинные слова. 40, 60 символов. Которые никак не лезут в отведённое им место и нормально не переносятся. Даже уменьшение шрифта не поможет, нужно перепиливать форму.

                    Далеко не всегда это требуется. Если дизайн и вёрстка заранее расчитаны под многоязычность, то с этим проблем нет. Как пример: booking.com, который нормально смотрится и с китайским, и с немецким.


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

                    Чаще всего это означает дополнительный класс rtl в body, а всё остальное переворачивается стилями. С этим проблем нет.


                    В восточно-азиатских языках (с иероглифами) другие виды списков, не такие, как у европейцев. См. тег <ruby>. Да там всё другое, те же даты записывают как-то так: 2018?8?7?.

                    Как я уже писал, это решается правильными библиотеками интернационализации, а не наколеночным склеиванием дня, месяца и года.


                    Во франции за коверканье языка штрафуют, и больно.

                    И правильно делают. А у нас бы взвыли, что притесняют свободу.


                    В ближневосточных языках не 2 набора букв (прописные/строчные), а 4, и за неверный выбор набора можно неиллюзорно огрести от имама.

                    А это, кстати, делается автоматически на уровне системного рендеринга шрифтов, т.е. это забота ОС и браузера.


              1. vanxant
                07.08.2018 21:31
                +1

                Я не предлагаю, я просто рассказываю, как это сделано в нормальных проектах.
                То, что миллионы быдлокодеров за фикс прайс с апворка делают иначе — не показатель.
                То, что так делают прыщавые стартаперы из долины, которым нужно быстро выкатить MVP для внутреннего рынка — не показатель. А потом им видите ли лень рефакторить своё уг, пусть эти аборигены жрут что дают.
                И да, plural forms решают проблему примерно никак.
                И да, переводчикам отдаётся только html-код (часть template в листинге в статье), но при желании они могут дописать кусок style. И они отлично умеют с этим работать.


                1. staticlab
                  07.08.2018 21:33

                  То есть все идиоты, одни мы умные? Лихо же вы всех назвали быдлокодерами. Сколько же вы таких "нормальных" проектов назвать можете?


                  1. vanxant
                    07.08.2018 21:44
                    +1

                    Ну как минимум это нормально сделано в vue, а до него в knockout.js. И автоматом во всех приложениях на них. Да блин, даже в Битриксе это реализовано нормально — там на каждый язык заводится отдельный «сайт» с отдельным шаблоном.
                    Если про игры говорить, то вот Ведьмак, например, сделан правильно. Линейка (ла2) и вообще игры ncsoft тоже. В-общем, всё, что сделано не американцами, как правило, таких проблем не имеет.


                    1. staticlab
                      07.08.2018 21:52

                      Так всё-таки как же во Vue отделить мух от котлет и сделать интернационализированную корзину?


                      Битрикс же сам по себе пример плохого дизайна системы. И я сомневаюсь, что подобная схема интернационализации в нём однажды не вылезет косяками в виде корявой локали в одном из компонентов или расхождения версий при редизайне.


                      И да, какая же всё-таки схема с переводами использована в Линейке и Ведьмаке?


                      1. vanxant
                        07.08.2018 22:49

                        Так всё-таки как же во Vue отделить мух от котлет и сделать интернационализированную корзину?

                        Да делайте как хотите. У вас на каждый язык — свой фрагмент html. Внутри вы можете дёргать любые функции (стандартные или свои), использовать условные и тернарные операторы, лепить нужные стили — всё, что вам угодно. И вся эта логика представления инкапсулирована в отдельном файле, никак не зависит от логики компонента и не мешает ни обновлению компонента, ни обновлению других языковых шаблонов.
                        Битрикс же сам по себе пример плохого дизайна системы.

                        Ну, конкретно в этом месте у них отличный дизайн. И да, они поддерживают «из коробки» 17, что-ли, языков — как в стандартных шаблонах, так и в админке. И вы ни на одном языке не увидите «2 товар(ов)». Ну, если внедряльщики не постараются.


                        1. staticlab
                          07.08.2018 23:16
                          +1

                          Да делайте как хотите. У вас на каждый язык — свой фрагмент html. Внутри вы можете дёргать любые функции (стандартные или свои), использовать условные и тернарные операторы, лепить нужные стили — всё, что вам угодно.


                          То есть вы предлагаете дёргать функции, условные и тернарные операторы непосредственно переводчику? И что делать, если на одной из страничек произошло какое-то изменение в структуре? Разработчик должен будет пройти по всем шаблонам и внести изменения? А там на каждой странице переводчик всё по-своему сделал. Или нам нужен переводчик-разработчик под каждую языковую версию?


                          Ну, конкретно в этом месте у них отличный дизайн. И да, они поддерживают «из коробки» 17, что-ли, языков — как в стандартных шаблонах, так и в админке. И вы ни на одном языке не увидите «2 товар(ов)». Ну, если внедряльщики не постараются.

                          Так в том и дело, что их поддержка языков в своих шаблонах и админках не имеет никакого отношения к контенту, который будет выводить разработчик. И как я понимаю, по крайней мере в 2014 году даже стандартной документированной функции для плюрализации в Битриксе не было, и разработчики делали такие вот костыли: https://dev.1c-bitrix.ru/community/webdev/user/157326/blog/10138/?commentId=54191 Несложно понять, что никакой реальной многоязычной поддержкой и не пахнет.


                          1. vanxant
                            07.08.2018 23:29

                            Да, если вы делаете локализованную версию нормального продукта и хотите её поддерживать, то вам в любом случае придётся держать в штате/на подхвате переводчиков. Потому как тексты меняются, появляются новые фичи, которые тоже нужно переводить и т.д.
                            И не надо считать технических переводчиков идиотами, как правило это инженеры, получившие второе образование (или типа того), а не просто какие-то там девочки «с филфака и в декрет». Разобраться чисто в html вёрстке и паре несложных функций они вполне могут. Ну, если мы про нормальный продукт говорим, а не про херак-херак и в продакшн, пусть пипл хавает.


                            1. staticlab
                              07.08.2018 23:34

                              В вашем варианте я вижу как минимум проблемы с версионированием и констистентностью перевода. Ну разумеется, если всё-таки разработчики не поленились вынести все текстовые строки в языковую базу.


                            1. staticlab
                              07.08.2018 23:43

                              Разобраться чисто в html вёрстке и паре несложных функций они вполне могут.

                              Справедливости ради, точно так же они могут поддерживать и React, и Angular, и Vue, и любые другие шаблоны.


                              1. vanxant
                                08.08.2018 01:59
                                -1

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


                                1. staticlab
                                  08.08.2018 09:38
                                  +1

                                  Я бы так не сказал. Не сложнее, чем в других фреймворках. Всё зависит от качества кода.


                      1. vanxant
                        07.08.2018 22:51

                        И да, какая же всё-таки схема с переводами использована в Линейке и Ведьмаке?

                        Вы таки не поверите, но там внутре все диалоги, формы и т.д. — это фрагменты html. Просто у каждого варианта, например, в диалоге прибит гвоздями уникальный id.


                        1. staticlab
                          07.08.2018 23:50

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


                          1. vanxant
                            08.08.2018 01:57

                            А никто не говорил, что оно не в базе хранится:) Разумеется, не в отдельных файлах на каждый предмет. Но — вместе с html тегами. Ну т.е. сама игра ожидает, что там фрагмент html, plain text это частный «нулевой» случай html.


                    1. faiwer
                      07.08.2018 21:59

                      Да да. Вспомнить только сколько было и есть багов, связанных с раскладками клавиатуры и горячими клавишами. И ведь именитые конторы и продукты! Я лично сталкивался с подобными проблемами от Adobe. И ладно бы горячие клавиши просто не работали, но блин были даже проблемы, когда что-то не работало если в имени профиля пользователя есть кириллица! Adobe! Ну как так? :) А QT4? А SublimeText? Да тысячи этих "кривых" приложений.


                      ПО написанное в чисто англоязычной компании с большой степенью вероятности огребает от всех возможных костылей связанных с локализацией, раскладками, RTL, fonts, etc.


                      1. staticlab
                        07.08.2018 22:16

                        Да, насчёт Adobe соглашусь, у них локализации очень кривые.


                        И ладно бы горячие клавиши просто не работали, но блин были даже проблемы, когда что-то не работало если в имени профиля пользователя есть кириллица!

                        Ой, а сколько было примеров глюков ПО, когда в профиле был пробел.


                        ПО написанное в чисто англоязычной компании с большой степенью вероятности огребает от всех возможных костылей связанных с локализацией, раскладками, RTL, fonts, etc.

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


                        1. faiwer
                          07.08.2018 22:21

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

                          Полагаю, что MS наступила на большую часть из этих граблей за свою долгую и богатую жизнь.


                          1. staticlab
                            07.08.2018 22:39
                            +1

                            Так ведь в том-то и дело! Моя позиция в том, что уже до нас кто-то неоднократно наступил на грабли i18n, и уже есть готовые решения, которыми лучше пользоваться, чем придумывать свой велосипед. Как раз пример с форматированием дат или денег в тему. Большинство даже русскоязычных разработчиков могут не догадаться, что нельзя просто склеить день, месяц и год.


                            Тупые же клоны страниц для каждого из языков в общем случае тоже решения не принесут. Цена поддержки такого проекта возрастёт во столько же раз. Если, например, вернуться к вашему примеру с датами "от-до", то может быть и есть смысл отдельной версии формы для казахского языка, но её тоже придётся не забывать поддерживать. Не у всех компаний на это может хватить ресурсов. Тут, как вариант, дизайнер может предложить просто убрать текст, оставив одно только тире (как это сделано, например, на Букинге). Но, разумеется, до варианта "5 товар(ов) в корзине" тоже опускаться не стоит. И, раз уж мы вспомнили про корзину, то языковые версии страниц сами по себе не просклоняют этот текст. Наоборот, если переводчиков оставили наедине с такой страницей, неизбежно появятся коверканья подобного рода. Примеры кустарных переводов в том числе игр это только подтверждают.


                    1. mayorovp
                      08.08.2018 09:12

                      Да, давайте вспомним про игры. Вот, например, Скайрим — игра с хорошей локализацией, перевели даже текстуры. Все как вы любите: отдельная версия всех файлов.

                      Но постойте! Почему при установке большинства англоязычных модов локализация сбивается и местами пропадает?


      1. 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.


        1. staticlab
          07.08.2018 22:21

          Кстати забавно, что если поднять холивары Angular.js vs React, то одним из аргументов реактистов было то, что Ангуляр вводит свой язык шаблонов, и его ещё нужно учить дополнительно, а в Реакте можно фигачить компоненты in-place, и это нормально, потому что это "не HTML", а просто другая форма записи вызова функции React.createElement.


          Теперь же маятник качается в обратную сторону :)


          1. faiwer
            07.08.2018 22:27

            Всё хуже. Тут недавно товарищ отстаивал позицию, что css-стили написанные через интерполяцию, с анонимными методами и вложенными тернарными операторами, в строках-шаблонах — читаются легче и лучше, чем в SCSS. А каждый топик про несчастный Svelte переполнен хейтерами любого возможного DSL. Дескать даёшь везде встраиваемый JS, пусть даже написанный ногами с нагромождением всех видов кавычек, скобок и хаков вроде && ... ||. Мол JS мы уже знаем. Бррр. Мне не понять. Я даже для тестов часто новый DSL создаю исходя из задачи. А тут шаг в лево, шаг в право, "мой редактор не умеет ваш суржик, закопать!".


            1. staticlab
              07.08.2018 22:42

              А тут шаг в лево, шаг в право, "мой редактор не умеет ваш суржик, закопать!".

              Интересно, что когда-то их любимый редактор его разработчики всё-таки учили корректно распознавать JSX, Styled-components и т.д. и т.п., да смесь JS и HTML как раз суржик и есть :)


  1. zogxray
    07.08.2018 17:07
    +1

    Vue проще, понятнее, лаконичнее и экономит время.