Язык программирования JavaScript(+его довольно «старенькая» библиотека jQuery) существует и активно используется программистами по всему миру довольно давно. JavaScript сегодня является самым популярным языком программирования, так как(по моему мнению) просто не имеет для себя альтернативы, как язык, который используется на front-end(в отличие, например, от целой группы back-end языков – Python, Java, C, PHP etc.).
Но сегодня знать(и уметь использовать) только native JS(назовем его так) стало недостаточно для соискателей на открытую вакансию front-end(full-stack) developer. Сейчас текст любой соответствующей вакансии обязательно содержит требование знания одного(а лучше - нескольких) из современных js-фреймворков, основные из которых это react.js(самый мощный и востребованный), vue.js(попроще и лучше документирован), angular.js(ниша использования которого, конечно, значительно уже).
В этой связи напрашивается вопрос «Почему же сейчас уже недостаточно простого native JS и нужен какой-то из его современных фреймворков?». В данной статье я постараюсь на реальном примере попробовать ответить на этот вопрос.
Во-первых, любой фреймворк(в любом языке программирования) нужен в качестве дополнения (!хочу подчеркнуть – именно «дополнения», т.е. нельзя «войти» в, например, react.js, если вы не владеете на достаточно хорошем уровне обычным native JS(events, DOM, class/extends, export/import)), которое упрощает и ускоряет написания кода.
Во-вторых, кроме упрощения/ускорения написания кода для современных(иногда очень сложных) front-приложений очень важен момент скорости работы данного приложения, даже если мы имеем дело с отображением на странице довольно большого объема информации.
По первому пункту можно упомянуть, например, дополнительные готовые библиотеки или компоненты, использование которых в значительной степени масштабирует и ускоряет разработку.
Но, в данной своей статье я хотел бы более подробно остановиться именно на втором моменте – скорости отображения большого объема данных, которые поступают с сервера и должны быть отображен на странице с минимальной задержкой.
И вот как раз для эффективного решения этой второй задачи все современные js-фреймворки используют такую(я считаю – самую полезную) свою опцию, как «реактивность».
Чтобы разобраться в сути «реактивности» (далее - на примере native JS vs react.js), давайте рассмотрим следующий пример.
Предположим, сайт имеет страницу корзины, куда попадают товары, которые выбрал пользователь:
Верстка одной строки корзины (т.е. для одного выбранного товара) выглядит следующим образом:
Пример кода 1.
<div class="row">
<div class="col-xl-3 border cart_product_img text-center p-2">
<img src="img/bg-img/cart3.jpg" alt="Product" />
</div>
<div class="col-xl-3 border cart_product_name p-2">
<h5>Minimal Plant Pot</h5>
</div>
<div class="col-xl-3 border cart_product_price p-2">
<h5>$180</h5>
</div>
…
</div>
По существующему алгоритму пользователь может удалить какой-то товар из корзины (красная кнопка в столбце Remove one). При этом после удаления данной записи из БД с использованием технологии ajax(т.е. без перезагрузки страницы) front с back-а получает текущее (после удаления) состояние корзины (т.е., например, было 3-и товара, удалили 1-н товар, с сервера поступает массив из 2-х оставшихся товаров – image, name, price). Далее(в соответствии с ajax-технологией) JS должен в цикле сформировать 2-а элемента верстки (Пример кода 1.), заполнив image, name, price данными, поступившими из БД. Для этого в native JS можно, например, написать функцию, использующую методы createElement, setAttribute, innerHTML, appendChild(или их аналоги из jQuery). Но это будет довольно непростой метод, содержащий около 30-и строк. Плюс при таком подходе (кроме сложности кода) падает скорость отображения пропорционально объему возвращаемых с массива данных.
А как можно ускорить/упростить этот процесс в react.js? Как уже говорилось выше, одно из главных достоинств современных js-фреймворков – «реактивность». Ее суть состоит в том, что в js-код вводится некая переменная-состояние:
Пример кода 2.
this.state = {
cartDataDb: [],
};
…и тут же в html-template react-кода(для тех, кто не знаком со структурой react-кода – html-верстка находится тут же в react-компоненте) стоит цикл(map), в котором формируется верстка строк корзины с заполнением данными из этой переменной-состояния (this.state.cartDataDb):
Пример кода 3.
{this.state.cartDataDb.map((item, key) =>
<div className="row" key={key}>
<div className="col-xl-3 border cart_product_img text-center p-2">
<img src={item.image} alt="Product" />
</div>
<div className="col-xl-3 border cart_product_name p-2">
<h5>{item.name}</h5>
</div>
<div className="col-xl-3 border cart_product_price p-2">
<h5>{item.price}</h5>
</div>
…
</div>
)}
Суть «реактивности» состоит в том, что как только в react-коде меняется переменная-состояние (Пример кода 2.), т.е. поступивший с сервера обновленный после удаления массив продуктов корзины присваивается ей, react моментально перерендеривае (перестраивает) html-верстку в своей компоненте(автоматом сработает map (Пример кода 3.)).
В результате имеем очевидный выигрыш – во-первых, проще реализация (без лишней native JS-функции с createElement, setAttribute, innerHTML, appendChild), во-вторых, «реактивная» мгновенная связь react-html-кода с react-js-кодом, которые находятся в одной и той же компоненте.