Lit против React: Руководство по сравнению

Автор Клара Экекента✏️

Выбор фронтенд-фреймворка может быть трудным решением для разработчика, потому что существует так много вариантов. React — один из самых популярных вариантов. Он хорошо зарекомендовал себя и имеет рейтинг удовлетворенности 84% по данным опроса 2021 года State of JS Survey. Тем не менее, существует несколько других фреймворков с интересными особенностями и функциональностью, которые стоит изучить.

При выборе фронтенд-фреймворка для своего следующего проекта обратите внимание на следующие вопросы:

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

Одной из альтернатив React является Lit, который имеет рейтинг удовлетворенности 77% по данным исследования 2021 State of JS Survey. Lit прост в освоении и использовании, а его небольшая площадь позволяет быстро загружать файлы.

В этом учебнике мы сравним React и Lit. Мы также создадим пример проекта на Lit.

Перейти вперед:

  • Что нового в Lit?
  • Lit против React
  • JSX и шаблонизация
  • Компоненты и реквизиты
  • Состояние и методы жизненного цикла
  • Хуки
  • Ссылки
  • Создание базового проекта в Lit
  • Стоит ли мне переходить с React на Lit?

Давайте начнем!

Что нового в Lit?

Lit имеет несколько особенностей, которые отличают его от других фронтенд-фреймворков:

  • Базовый класс LitElement — это удобное и универсальное расширение родного HTMLElement. Этот класс может быть расширен для определения наших компонентов
  • Выразительные и декларативные шаблоны позволяют легко определить, как компонент должен быть отображен.
  • Реактивные свойства — это внутреннее состояние компонентов Lit. Компоненты автоматически перерисовываются при изменении реактивного свойства
  • Масштабируемые стили помогают сохранить простоту селекторов CSS, гарантируя, что стили компонентов не влияют на другие контексты.
  • Поддерживает Vanilla Javascript, TypeScript и эргономику (декораторы и объявления типов).

Lit против React

Основные концепции и возможности Lit во многом схожи с концепциями и возможностями React, но есть и существенные различия. Например, React существует с 2013 года и гораздо более популярен, чем Lit. На момент написания статьи React имеет около 15,9 миллионов еженедельных загрузок на npm по сравнению с 127 тысячами еженедельных загрузок на npm для Lit.

Однако Lit быстрее React и занимает меньше памяти. Публичное сравнение бенчмарков показало, что lit-html на 8-10 процентов быстрее, чем VDOM от React. Объем памяти Lit составляет 5 кБ, по сравнению с 40 кБ для React.

Эти два фреймворка предлагают и другие интересные возможности. Давайте посмотрим, как они сравниваются.

JSX и шаблонизация

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

Вот пример шаблонизации JSX в React:

import 'react';
import ReactDOM from 'react-dom';

const name = 'World';
const el = (
  <>
    <h1>Hello, {name}</h1>
    <div>How are you? </div>
  </>
);
ReactDOM.render(
  el,
  mountNode
);
Вход в полноэкранный режим Выход из полноэкранного режима

А вот пример шаблонизации в Lit:

import {html, render} from 'lit';

const name = 'World';
const el = html`
  <h1>Hello, ${name}</h1>
  <div>How are you?</div>`;

render(
  el,
  mountNode
);
Вход в полноэкранный режим Выход из полноэкранного режима

Как видно из приведенных примеров, Lit не нужен фрагмент React для группировки нескольких элементов в своих шаблонах. Вместо этого шаблоны Lit обернуты HTML-тегированным литералом шаблона.

Компоненты и реквизиты

Компоненты — это самодостаточные, многократно используемые фрагменты кода. Они выполняют те же действия, что и функции JavaScript, но работают независимо и возвращают HTML. Компоненты React делятся на два типа: компоненты классов и функциональные компоненты.

Компоненты класса

Lit-эквивалент компонента класса React называется LitElement.

Вот пример компонента на основе класса в React:

import React from 'react';
import ReactDOM from 'react-dom';

class Welcome extends React.Component {
  constructor(props) {
    super(props);
    this.state = {name: ''};
  }

  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

const el = <Welcome name="World"/>
ReactDOM.render(
  el,
  mountNode
);
Вход в полноэкранный режим Выход из полноэкранного режима

Вот тот же пример в Lit с использованием LitElement:

import {LitElement, html} from 'lit';

class WelcomeBanner extends LitElement {
  static get properties() {
    return {
      name: {type: String}
    }
  }

  constructor() {
    super();
    this.name = '';
  }

  render() {
    return html`<h1>Hello, ${this.name}</h1>`
  }
}

customElements.define('welcome-banner', WelcomeBanner);
Вход в полноэкранный режим Выход из полноэкранного режима

После определения и рендеринга шаблона для компонента LitElement мы добавляем следующее в наш HTML-файл:

<!-- index.html -->
<head>
  <script type="module" src="./index.js"></script>
</head>
<body>
  <welcome-banner name="World"></welcome-banner>
</body>
Вход в полноэкранный режим Выйти из полноэкранного режима

Теперь давайте рассмотрим, как создаются функциональные компоненты в этих фреймворках.

Функциональные компоненты

Lit не использует JSX, поэтому нет корреляции один к одному с функциональным компонентом React. Однако проще написать функцию, которая принимает свойства и затем рендерит DOM на основе этих свойств.

Вот пример функционального компонента в React:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const el = <Welcome name="World"/>
ReactDOM.render(
  el,
  mountNode
);
Вход в полноэкранный режим Выход из полноэкранного режима

Вот тот же пример в Lit:

import {html, render} from 'lit';

function Welcome(props) {
  return html`<h1>Hello, ${props.name}</h1>`;
}

render(
  Welcome({name: 'World}),
  document.body.querySelector('#root')
);
Вход в полноэкранный режим Выход из полноэкранного режима

Состояние и методы жизненного цикла

state — это объект React, который содержит данные или информацию о компоненте. Состояние state компонента может изменяться с течением времени. Каждый раз, когда его state изменяется, компонент перерисовывается.

Реактивные свойства Lit — это смесь state и props от React. При изменении реактивные свойства могут запустить жизненный цикл компонента, повторно отображая компонент и, по желанию, считывая или записывая атрибуты. Реактивные свойства бывают двух видов:

  • Публичные реактивные свойства
  • Внутреннее реактивное состояние

Реактивные свойства реализуются в React следующим образом:

import React from 'react';

class MyEl extends React.Component {
  constructor(props) {
    super(props)
    this.state = {name: 'there'}
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.name !== nextProps.name) {
      this.setState({name: nextProps.name})
    }
  }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Реактивные проепринты реализованы в Lit, например, так:

import {LitElement} from 'lit';
import {property} from 'lit/decorators.js';

class MyEl extends LitElement {
  @property() name = 'there';
}
Войти в полноэкранный режим Выход из полноэкранного режима

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

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

constructor

Метод constructor доступен как в React, так и в Lit. Он автоматически вызывается при создании объекта из класса.

Вот пример метода constructor в React:

import React from 'react';
import Chart from 'chart.js';

class MyEl extends React.Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
    this._privateProp = 'private';
  }
Вход в полноэкранный режим Выход из полноэкранного режима

Вот пример метода constructor в Lit:

class MyEl extends LitElement {
  static get properties() {
    return { counter: {type: Number} }
  }
  constructor() {
    this.counter = 0;
    this._privateProp = 'private';
  }
Вход в полноэкранный режим Выход из полноэкранного режима

render

Метод render доступен как в React, так и в Lit. Он отображает код внутри указанного элемента.

Вот пример метода render в React:

render() {
    return <div>Hello World</div>
  }
Вход в полноэкранный режим Выход из полноэкранного режима

Вот пример метода render в Lit:

render() {
    return html`<div>Hello World</div>`;
  }
Вход в полноэкранный режим Выход из полноэкранного режима

componentDidMount против firstUpdated и connectedCallback

Функция componentDidMount в React похожа на комбинацию обратных вызовов жизненного цикла Lit’s firstUpdated и connectedCallback. Эта функция вызывается после подключения компонента.

Вот пример метода componentDidMount в React:

componentDidMount() {
    this._chart = new Chart(this.chartElRef.current, {...});
  }

  componentDidMount() {
    this.window.addEventListener('resize', this.boundOnResize);
  }
Вход в полноэкранный режим Выход из полноэкранного режима

Вот пример обратных вызовов жизненного цикла firstUpdated и connectedCallback в Lit:

firstUpdated() {
    this._chart = new Chart(this.chartEl, {...});
  }

  connectedCallback() {
    super.connectedCallback();
    this.window.addEventListener('resize', this.boundOnResize);
  }
Вход в полноэкранный режим Выход из полноэкранного режима

componentDidUpdate vs. updated

Функция componentDidUpdate в React эквивалентна updated в Lit. Она вызывается после изменения реквизитов или состояния компонента.

Вот пример метода componentDidUpdate в React:

componentDidUpdate(prevProps) {
    if (this.props.title !== prevProps.title) {
      this._chart.setTitle(this.props.title);
    }
  }
Вход в полноэкранный режим Выход из полноэкранного режима

Вот пример метода updated в Lit:

updated(prevProps: PropertyValues<this>) {
    if (prevProps.has('title')) {
      this._chart.setTitle(this.title);
    }
  }
Вход в полноэкранный режим Выход из полноэкранного режима

componentWillUnmount vs.disconnectedCallback

Функция componentWillUnmount в React эквивалентна disconnectedCallback в Lit. Эта функция вызывается после уничтожения или размонтирования компонента.

Вот пример метода componentWillUnmount в React:

componentWillUnmount() {
    this.window.removeEventListener('resize', this.boundOnResize);
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Вот пример метода disconnectedCallback в Lit:

disconnectedCallback() {
    super.disconnectedCallback();
    this.window.removeEventListener('resize', this.boundOnResize);
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Крючки

Хуки — это функции, которые позволяют функциональным компонентам React «подключаться» к состоянию React и функциям жизненного цикла. Хуки не работают внутри классов, но они позволяют нам использовать React без классов.

В отличие от React, Lit не предлагает способ создания пользовательских элементов из функции, но LitElement решает большинство основных проблем с компонентами классов React:

  • Не принимает аргументы в конструкторе
  • Автоматическая привязка всех @event привязок (как правило, к ссылке на пользовательский элемент)
  • Инстанцирование свойств класса в качестве членов класса

Вот пример хуков в React (на момент создания хуков):

import React from 'react';
import ReactDOM from 'react-dom';

class MyEl extends React.Component {
  constructor(props) {
    super(props); // Leaky implementation
    this.state = {count: 0};
    this._chart = null; // Deemed messy
  }

  render() {
    return (
      <>
        <div>Num times clicked {count}</div>
        <button onClick={this.clickCallback}>click me</button>
      </>
    );
  }

  clickCallback() {
    // Errors because `this` no longer refers to the component
    this.setState({count: this.count + 1});
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Вот тот же пример с использованием LitElement:

class MyEl extends LitElement {
  @property({type: Number}) count = 0; // No need for constructor to set state
  private _chart = null; // Public class fields introduced to JS in 2019

  render() {
    return html`
        <div>Num times clicked ${count}</div>
        <button @click=${this.clickCallback}>click me</button>`;
  }

  private clickCallback() {
    // No error because `this` refers to component
    this.count++;
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Refs

Refs — это функции React, которые позволяют нам получить доступ к элементу DOM и любым элементам React, которые мы создали. Они используются, когда мы хотим изменить значение дочернего компонента без использования props.

В Lit рефссылки создаются с помощью декораторов @query и @queryAll. Эти декораторы почти эквивалентны querySelector и querySelectorAll, соответственно, и выводятся непосредственно в DOM.

Вот пример функции refs в React:

const RefsExample = (props) => {
 const inputRef = React.useRef(null);
 const onButtonClick = React.useCallback(() => {
   inputRef.current?.focus();
 }, [inputRef]);

 return (
   <div>
     <input type={"text"} ref={inputRef} />
     <br />
     <button onClick={onButtonClick}>
       Click to focus on the input above!
     </button>
   </div>
 );
};
Вход в полноэкранный режим Выход из полноэкранного режима

Вот тот же пример в Lit с использованием декоратора @query:

@customElement("my-element")
export class MyElement extends LitElement {
  @query('input') // Define the query
  inputEl!: HTMLInputElement; // Declare the prop

  // Declare the click event listener
  onButtonClick() {
    // Use the query to focus
    this.inputEl.focus();
  }

  render() {
    return html`
      <input type="text">
      <br />
      <!-- Bind the click listener -->
      <button @click=${this.onButtonClick}>
        Click to focus on the input above!
      </button>
   `;
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Создание базового проекта дел в Lit

Давайте посмотрим на Lit в действии, создав пример проекта дел.

Для начала выполните команду для клонирования стартового JavaScript-проекта Lit:

git clone https://github.com/lit/lit-element-starter-js.git
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем перейдите в папку проекта и установите необходимые пакеты с помощью этой команды:

npm install
Enter fullscreen mode Выйти из полноэкранного режима

После завершения установки перейдите к файлу lit-element-starter-js/my-element.js. Удалите коды boilerplates и создайте компонент Todo со следующим фрагментом кода:

import {LitElement, html, css} from 'lit';
class Todo extends LitElement {
  constructor() {
    super();
  }
  render() {
    return html`
      <div class="todos-wrapper">
        <h4>My Todos List</h4>
        <input placeholder="Add task..."/>
        <button>Add</button>
        <div class="list">
            #Todo List
        </div>
      </div>
    `;
  }
}
customElements.define('my-element', Todo);
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенный выше код создает компонент Todo с методом constructor, где будут определены все реактивные свойства приложения, и методом render, который рендерит JSX, содержащий поле ввода и кнопку.

Далее определим свойства приложения. Поскольку это приложение для выполнения дел, нам понадобится TodosList для хранения задач и свойство input для получения пользовательского ввода.

Теперь добавим приведенный ниже фрагмент кода в класс Todos:

static properties = {
    TodosList: {type: Array},
    input: {type: String},
  };
Вход в полноэкранный режим Выйти из полноэкранного режима

Затем с помощью приведенного ниже кода присвоим начальные значения свойствам TodosList и input в методе constructor:

 this.TodosList = [];
 this.input = null;
Войти в полноэкранный режим Выход из полноэкранного режима

Далее мы создадим метод для добавления и обновления задач:

setInput(event) {
    this.input = event.target.value;
  }

  addTodo() {
      this.TodosList.push({
      name: this.input,
      id: this.TodosList.length + 1,
      completed: false,
    });
    this.requestUpdate();
  }

 updateTodo(todo) {
    todo.completed = !todo.completed;
    this.requestUpdate();
  }
Войти в полноэкранный режим Выход из полноэкранного режима

В приведенном выше коде видно, что функция requestUpdate() была вызвана в методах addTodo и updateTodo после изменения состояния. Эти методы изменяли свойство TodosList, поэтому мы вызвали функцию requestUpdate() для обновления состояния компонента.

Далее мы изменим метод render, чтобы добавить слушателей событий к методам, созданным выше, и отобразить задачи дел.

 render() {
    return html`
      <div class="todos-wrapper">
        <h4>My Todos List</h4>
        <input placeholder="Add task..." @input=${this.setInput} />
        <button @click=${this.addTodo}>Add</button>
        <div class="list">
          ${this.TodosList.map(
            (todo) => html`
              <li
                @click=${() => this.updateTodo(todo)}
                class=${todo.completed && 'completed'}
              >
                ${todo.name}
              </li>
            `
          )}
        </div>
      </div>
    `;
  }
Вход в полноэкранный режим Выход из полноэкранного режима

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

static styles = css`
    .todos-wrapper {
      width: 35%;
      margin: 0px auto;
      background-color: rgb(236, 239, 241);
      padding: 20px;
    }
    .list {
      margin-top: 9px;
    }
    .list li {
      background-color: white;
      list-style: none;
      padding: 6px;
      margin-top: 3px;
    }
    .completed {
      text-decoration-line: line-through;
      color: #777;
    }
    input {
      padding: 5px;
      width: 70%;
    }
    button {
      padding: 5px;
    }
  `;
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь давайте запустим приложение:

npm run serve
Войти в полноэкранный режим Выйти из полноэкранного режима

Вот наш пример проекта!

Стоит ли мне переходить с React на Lit?

У каждого фреймворка есть свои сильные и слабые стороны. На React работают веб-приложения многих крупных компаний, таких как Facebook, Twitter и Airbnb. Кроме того, у него обширное сообщество разработчиков и соавторов.

Если вы сейчас используете React и довольны этим выбором, то я не вижу причин для перехода. Однако если вы работаете над проектом, требующим действительно высокой производительности, то вам стоит рассмотреть возможность использования Lit.

Чтобы узнать больше о Lit, ознакомьтесь с его официальной документацией.


Полная видимость производственных приложений React

Отладка приложений React может быть сложной задачей, особенно когда пользователи сталкиваются с проблемами, которые трудно воспроизвести. Если вы заинтересованы в мониторинге и отслеживании состояния Redux, автоматическом обнаружении ошибок JavaScript, отслеживании медленных сетевых запросов и времени загрузки компонентов, попробуйте LogRocket.

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

Пакет промежуточного ПО LogRocket Redux добавляет дополнительный уровень видимости пользовательских сессий. LogRocket регистрирует все действия и состояние ваших хранилищ Redux.

Модернизируйте способы отладки приложений React — начните мониторинг бесплатно.


Полная видимость производственных приложений React

Отладка приложений React может быть сложной задачей, особенно когда пользователи сталкиваются с проблемами, которые трудно воспроизвести. Если вы заинтересованы в мониторинге и отслеживании состояния Redux, автоматическом выявлении ошибок JavaScript, отслеживании медленных сетевых запросов и времени загрузки компонентов, попробуйте LogRocket.

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

Пакет промежуточного ПО LogRocket Redux добавляет дополнительный уровень видимости пользовательских сессий. LogRocket регистрирует все действия и состояние ваших хранилищ Redux.

Модернизируйте отладку приложений React — начните мониторинг бесплатно.

Оцените статью
Procodings.ru
Добавить комментарий