Pull to refresh

Про реакт обзорно

Level of difficultyEasy

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

Небольшое оглавление:

1. Что такое React?

2. Отличия React от ванильных html/css/js

3. Внутрянка React-приложения

4. Минусы использования

5. Некоторые итоги

Что такое React?

Следует начать с прямого определения того, чем является данная технология. React - это библиотека, которая берет за основу такой язык программирования как js (либо ts) а так же имеет свой собственный "язык" - JSX (который на самом деле не является языком, об этом позже) и которая позволяет создавать динамичные, высокопроизводительные пользовательские интерфейсы как в браузерах, так и нативно на мобильных устройствах (благодаря технологии React Native).

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

Отличия React от ванильных html/css/js

Если вам удосуживалось когда-либо верстать сайты-визитки или лендинги, то вы, наверняка, знакомы с устройством статических веб-страниц: скелет-разметка сайта, написанная на html, внешнее оформление этого скелета в виде стилей css, а так же оживление этого сайта путем javascript. В данном случае React всего лишь несколько изменяет данный процесс: вместо отдельного написания сначала разметки, затем стилизации отдельных классовых html элементов и придачи им динамики при помощи ванильного Javascript, React позволяет централизованно и параллельно создавать ту же разметку, задавать ей внешнее представление и придавать ей живности в рамках одного-двух файлов.

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

1) Сначала браузер клиента получает все необходимые для работы файлы: html, css, javascript.

2) Браузер начинает построение разметки сайта, он анализирует html код и помещает в DOM все элементы в нужном порядке.

3) Затем браузер сопоставляет элементам их стили.

4) Далее браузер вешает прослушиватели событий (event listeners на элементы, если у них таковые имеются)

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

5) Сайт отобразился полностью и готов к работе.

Так выглядит генерация страницы при классическом методе верстки страниц.

В случае с React данная схема выглядит немного иначе:

1) В браузер клиента все так же приходят необходимые файлы для работы, но в данном случае ими являются заранее скомпилированные javascript файлы, которые в этот же момент начинают свой рантайм при попадании в браузер.

Минимизированный js файл, приходящий в браузер
Минимизированный js файл, приходящий в браузер

2) При помощи этих скриптов строится DOM страницы, элементам даются стили, параллельно React-приложение строит свое собственное Virtual DOM-дерево, которое понадобится ему для ререндера компонентов. По тому же Virtual DOM React генерирует реальный DOM и вставляет его в HTML-документ, обычно в элемент с id="root".

"Пустое" React-приложение, в котором имеется только root-элемент.
"Пустое" React-приложение, в котором имеется только root-элемент.

3) Затем происходит так называемая "гидрация" компонентов, по сути, то же навешивание слушателей событий.

4) React-приложение готово к работе.

Кстати в данной схеме я описал CSR (Client-Side-Rendering), когда сайт генерируется на стороне клиента, а не на сервере (SSR) (Возможно, этому будет посвящена статья)

Из данного сравнения видны отличия сайтов, написанных традиционным методом и при помощи React.

Следующие особенности React можно отнести к его отличиям а так же к его плюсам:

1) Компонентный подход: вместо написания единой html разметки мы создаем "кирпичи" - компоненты, которыми можно строить разметку приложения и эффективно переиспользовать, что существенно помогает соблюдать принцип DRY. Таким образом компонент инкапсулирует в себе разметку, стилизацию и логику, что очень удобно.

2) Из первой особенности вытекает уменьшение общего количества кода проекта, так как мы сокращаем html бойлерплейт (в свою очередь React требует свой собственный бойлерплейт и при помощи некоторых сборщиков и пакетов имеет свой скаффолдинг).

3) Одна из важнейших вещей компонентного подхода, который позволяет осуществить React, является управление состояниями компонентов, которые как раз придают этим компонентам динамику и интерактивность. Хранение состояний и управление ими в рамках компонентов реализуется с помощью так называемых хуков.

4) React-приложение генерируется на клиенте значительно быстрее, чем ванильно-реализованная страница, это достигается за счет того, что React-приложение создается из тех самых заранее скомплированных и минимизированных js скриптов, получаемых браузером. В добавок Virtual DOM реакта позволяет сократить количество операций над реальным DOM (в этом ему так же помогает движок Fiber, который находится в его ядре)

Внутрянка React

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

Структура проекта
Структура проекта
  1. .vscode - папка конфигурации настроек IDE, в котором ведется разработка, никак не связан с React.

  2. node_modules - папка, которая содержит в себе пакеты, необходимые для работы всего, важно упомянуть, что данную папку необходимо помещать в .gitignore, чтобы не захламлять удаленный репозиторий (к тому же если вес данной папки достаточно высок, то запушить файлы в репозиторий может даже не получиться)

  3. package.json - файл конфигурации проекта (его название, версия, некоторые другие метаданные, конфигурация алиасов для дев скриптов, внутренние зависимости и тд)

  4. package-lock.json - хранит историю зависимостей в проекте.

  5. vite.config.js - конфиг сборщика проекта, который позволяет собирать код React и запускать приложение. В качестве сборщика в проекте использован Vite, так же существуют такие сборщики как Webpack, CRA (устарел)

  6. .eslintrc.cjs - линтер, который помогает писать код в соответствии стандартам ES6 и подсвечивает ошибки. При грамотной настройке позволяет делать автофиксы после сохранения изменений в файле.

А теперь коснемся тех файлов, находящихся в папке src, которые служат точкой входа в React-приложение:

  1. index.html - файл первоначальной разметки, в которой содержится рутовый элемент, в который React вставит разметку после вычислений в Virtual DOM.

  2. main.jsx - скрипт, который рендерит приложение внутрь root-элемента:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

3. App.jsx - первый компонент React-приложения, который содержит в себе все остальные компоненты:

const App = () => {
  return <h1>Hello World</h1>
}

export default App

А вот как выглядит компонент, имеющий дочерние компоненты:

import CardButton from ' .. /CardButton/CardButton';
import styles from './JournalAddButton.module.css';

const JournalAddButton = () => {
  return (
  <CardButton className={styles['journal-add']}>
    <img src="/plus-icon.svg" alt="" />
    Новая заметка
  </CardButton>
  );
};

export default JournalAddButton;

Прошу обратить внимание на данный блок кода:

import React from 'react'; // Импорируется React, из которого берется метод createElement
import './App.css';

function App() {

  return React.createElement('div', {},
    React.createElement('h1', {}, 'Текст заголовка тэra h1'),
    React.createElement('h1', {}, 'Текст заголовка тэrа h1'),
    React.createElement('h1', {}, 'Текст заголовка тэга h1'),
  ); // JSX - это синтаксический сахар для вот такого рода функции, возвращает html элемент
     // createElement не может вернуть tuple из двух и более объектов

    // То же самое но только на JSX:
  return (
    <React.Fragment>
      <div>
      <h1>Текст заголовка тэга h1</h1>
      <h1>Текст заголовка тэга h1</h1>
      <h1>Тест заголовка тэга h1</h1>
      </div>
    </React.Fragment>
    );
};

export default App;

Из данного блока кода можно понять, что JSX - это все таки не язык, а синтаксический сахар - обертка над реальным кодом, который выполняет React при рендеринге компонента. Если в компоненте имеются вложенные компоненты, то он выполняет ту же самую процедуру, тем самым вкладывая функции сreateElement одну в другую, что очень быстро превращается в нечитаемую матрешку.

А теперь небольшой цикл работы React:

1) Реакт находит самый верхний компонент-родитель, запускает его функцию, и поэтапно вызывает соответствующие функции дочерних компонентов, параллельно строя свой Virtual DOM.
2) Когда реакт построил свое дерево, он создает реальное DOM дерево и помещает его в документ. (вмонтирование)
3) Если в каком-нибудь компоненте случились изменения (пользователь куда-нибудь кликнул), или какой-либо компонент вообще удалился, React сравнивает новое и предыдущее деревья, находит в них отличающиеся элементы и минимально обновляет реальный DOM, применяя только те изменения, которые были найдены на этапе сравнения (патчинг)

Вот так в упрощенном виде выглядит рендеринг в React-приложении.

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

Минусы использования React

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

1) React - это библиотека, а не полноценный фреймворк. При разработке в проект приходится интегрировать дополнительные библиотеки для решения таких задач, как маршрутизация, управление глобальными состояниями и обработка побочных эффектов. Это добавляет сложность в первоначальной настройке и архитектуре приложения.

2) Сложности с SEO: по умолчанию react-приложение рендерится на стороне клиента, что может затруднять индексацию страниц поисковыми системами. Это может потребовать настройки серверного рендеринга (например с этим справляется Next.js) для улучшения SEO.

3) Хоть это в общем распространяется на весь фронтэнд, но в плоскости реакта эта проблема становится более явной - отсутствие единых стандартов реализации. В реакте очень много способов решить одну и ту же проблему, и очень часто сложно найти единственно правильный, таким образом это затрудняет разработку и обучение в целом.

Некоторые итоги

Я не затронул еще очень много тонкостей и моментов, моя цель была обзорно показать, что из себя представляет React и в каких местах он соприкасается с традиционными методами верстки. Если вам понравилась данная статья, то можете оставить обратный отзыв, указать на ошибки, поделиться с теми, кого может заинтересовать данная тема.

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.