Добро пожаловать в мир React

Сейчас вы на каждом шагу вы слышите: “React! Виртуальный DOM! Компоненты! JSX!”. Настало время внести ясность, что это такое, как с этим жить и работать.

Виртульный DOM

DOM до безобразия медленный. Это не секрет. Особенно хорошо вы можете это заметить при работе с большими объемами данных. Долгое время разработчикам с этим приходилось мириться, пока не пришёл он, супергерой React. В наши руки попал очень мощный инструмент — виртуальный DOM, который позволяет значительно уменьшить количество перерисовок и обращений к DOM дереву.

Разберём стандартную ситуацию. Представьте, что вы владелец крупного интернет-магазина и решили отображать на одной странице данные о всех ваших клиентах (число переваливает за несколько тысяч). Данные получаете с сервера (AJAX или JSONP) и отрисовываете их с помощью JavaScript на странице (например, вот так). Вы посылаете запрос на сервер каждую секунду и полностью обновляете все данные, так как не знаете, что изменилось. В результате каждую секунду вам необходимо заново отрисовать на странице несколько тысяч DOM элементов. Но зачастую большая часть данных остаётся неизменной и получается так, что из-за одного-двух значений приходится перерисовывать все остальные.

Гораздо логичнее было бы получить данные и сравнить их с более ранними, а потом отрендерить на страницу только разницу. Например, при очередном запросе пользователи под номерами 24, 678 и 3391 сделали заказ, значит и изменить нужно только те элементы, которые принимают непосредственное участие в отображении информации об этих пользователях. Именно этим и занимается React со своим виртуальным DOM.

Чтобы понять, как это происходит, достаточно представить себе структуру обычного документа, точнее то, как её видит браузер. window, document, все DOM элементы для браузера являются не более, чем обычными объектами (у некоторых подобное заявление вызывает шок и заставляет хорошенько задуматься). Такая “особенность” строения документа позволяет создать очень похожую виртуальную структуру и держать её в памяти в виде простых объектов, не являющихся DOM элементами. В случае же когда необходимо внести изменения сначала происходит сравнение с виртуальной копией, вычисляется разница, после чего эта самая разница и передаётся в реальный DOM. В результате мы имеем сверхбыстрые приложения с самым минимальным количеством перерисовок.

Но и это ещё не всё! Самое прекрасное в использование React не сам виртуальный DOM, а то, что вам абсолютно не нужно ничего делать самостоятельно. Любой компонент, созданный с помощью React, уже работает с виртуальным DOM. Таким образом, вы получаете возможность не думать о производительности при работе с DOM элементами — React всё сделает за вас максимально качественно и быстро, и вы сможете сосредоточиться на действительно важных задачах, а не бороться с оптимизацией.

Мир компонентов

Всё, что вы создаёте при работе с React является компонентом. Что такое компонент? Всё просто. Компонент — обычный JavaScript файл, содержащий JSX разметку и всю логику, необходимую для работы (в идеале ещё и все CSS правила). На первый взгляд всё кажется сложнее, чем есть на самом деле, поэтому начнём с простого примера обычной кнопки, увеличивающей счётчик по клику (живой пример на jsbin):

import React, { Component } from 'react';
import { render } from 'react-dom';
class Button extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: this.props.start
    };
  }
  increment() {
    this.setState({
      count: this.state.count + 1
    });
  }
  render() {
    return (
      <button onClick={this.increment.bind(this)} className="button">
        Button was clicked {this.state.count} times
      </button>
    );
  }
}
render(<Button start={10} />, document.getElementById('btn'));

Состояние

Итак, компонент-кнопка, самый простой пример, который только можно придумать. Тем не менее, на столь малом количестве кода можно проиллюстрировать многие особенности работы с React. Начнём с состояния:

this.state = {
  count: this.props.start
};

Задавая свойство state для текущего класса, вы говорите реакту: “Это данные, за которыми стоит следить”. При изменении состояния React будет проводить свои магические манипуляции с виртуальным DOM и заново рендерить все изменившиеся элементы. При использовании свойства state необходимо придерживаться одного простого правила: состояние задаётся присваиванием всего один раз при инициализации компонента. Другими словами, не стоит присваивать значения напрямую, а вместо этого использовать функцию setState:

// Плохо
this.state.count = 0;

// Хорошо
this.setState({
  count: 0
}); 

Для изменения состояния чаще всего удобно создать отдельный метод, для кнопки подобный метод — increment, который и увеличивает счётчик на единицу:

increment() {
  this.setState({
    count: this.state.count + 1
  });
}

С помощью свойства this.state.count мы получаем текущее значение, прибавляем к нему единицу и заново устанавливаем состояние. Но выше же было написано, что нельзя обращаться к свойствам объекта this.state! Можно. Но только в том случае, если вы хотите получить значение, а не перезаписать его.

JSX

Непривычно писать HTML-разметку в JavaScript коде? Вы скоро привыкните и поймёте, что это очень удобно. На самом деле, всё, что возвращает метод компонентов render не более, чем шаблон, который вы хотите увидеть на странице. Другими словами, здесь работает обычная шаблонизация, которую, ко всему прочему, ещё и чрезвычайно удобна в использовании. На примере кнопки можно проследить немногое из того, на что способен JSX: создание DOM элементов, добавление обработчиков событий, создание атрибутов для элемента (вроде class) и наполнение элемента содержимым (другими DOM элементами или обычным текстом). Всё это не выглядит таким впечатляющим, пока мы не дойдём до самой сути: все значения, находящиеся в {фигурных скобках} будут вычислены. Например, в любом месте вы можете написать {2 + 3} и получить число 5. Разумеется, вы можете использовать и более сложные вычисления, вставлять свои переменные и функции, как и в приведённом выше примере:

<button onClick={this.increment.bind(this)} className="button">
  Button was clicked {this.state.count} times
</button>

Свойства компонентов

Неплохо было бы ещё сделать и так, чтобы при инициализации компонента можно было передать какие-либо стартовые значения. Сделать это очень просто: достаточно создать нечто похожее на атрибут и передать в него значение:

<Button start={10} />
//      ^^^^^ Настройка для компонента <Button />

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

class Button extends Component {
  constructor(props) {
    super(props);
    // после вызова super можно получить все свойства
    // с помощью this.props.prop_name
    this.state = {
      count: this.props.start
    };
  }
}

Рендеринг

Мы создали компонент, это уже хорошо. Но React пока не знает, что с ним делать. Чтобы увидеть результат нашей работы во всей красе необходимо сообщить библиотеке react-dom, что надо всё это дело отрендерить и показать. Делается это очень просто с помощью функции render, которую мы предварительно изъяли из библиотеки: первым параметром функция принимает компонент, который нужно отрендерить, вторым — DOM элемент (или элемнты) в которых нужно отрендерить данный компонент:

render(<Button start={10} />, document.getElementById('btn'));

Итого

  • React предназначен для создания максимально быстрых приложений. И в этой быстроте виноват никто иной, как виртуальный DOM.
  • “Единицей измерения” приложения на React является компонент.
  • Компонент является чем-то законченным и содержит всю разметку и логику, необходимые для существования компонента вне какого-либо приложения. В идеале компонент содержит и все связанные с ним CSS стили.
  • Любой компонент контролируется состоянием, при изменении которого происходит ререндеринг компонента

Комментарии