Владислав Калачев

React под капотом: как работает, разбираем код исходников

0

React — это одна из самых популярных библиотек для создания пользовательских интерфейсов. Но что делает React таким быстрым и гибким? Как React 18 справляется с обновлениями и рендерингом? Давайте заглянем «под капот» и разберемся, как работает React, исследуя его исходный код и принципы, на которых он основан.

Основные концепции и архитектура React

React построен на нескольких ключевых принципах: Virtual DOM, Reconciliation (согласование), Fiber и Concurrent Mode. Эти концепции обеспечивают высокую производительность и эффективность обновления интерфейса.

Virtual DOM

Virtual DOM — это легковесное представление реального DOM. React создает и хранит виртуальную копию DOM в памяти и сравнивает ее с предыдущим состоянием, чтобы минимизировать количество операций с реальным DOM. Эта технология называется Reconciliation.

Пример использования Virtual DOM:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default Counter;

Здесь React создает виртуальное представление компонента Counter и обновляет DOM, только если состояние изменяется.

Fiber: Новая реализация ядра React

Fiber — это новая архитектура ядра React, введенная в версии React 16 и улучшенная в React 18. Fiber позволяет разбивать обновления на части и выполнять их асинхронно, делая интерфейс более отзывчивым.

Как работает Fiber?

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

Concurrent Mode: Реактивное обновление интерфейса

В React 18 был добавлен Concurrent Mode, который позволяет React приостанавливать обновления, выполнять их по мере поступления данных и поддерживать приложение отзывчивым.

Пример с использованием startTransition в React 18:

import React, { useState, startTransition } from 'react';

function SearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value);

    // Используем startTransition, чтобы обновление результата было низкоприоритетным
    startTransition(() => {
      const filteredResults = fetchResults(value); // Функция для фильтрации данных
      setResults(filteredResults);
    });
  };

  return (
    <div>
      <input type="text" value={query} onChange={handleChange} />
      <ul>
        {results.map((result) => (
          <li key={result.id}>{result.name}</li>
        ))}
      </ul>
    </div>
  );
}

export default SearchComponent;

Здесь startTransition позволяет отложить обновление результатов поиска, чтобы более важные задачи (например, ввод текста) выполнялись без задержек. Это — одна из ключевых новинок React 18, которая позволяет управлять приоритетами обновлений.

Реализация Reconciliation (согласование)

Согласование (Reconciliation) — это процесс, с помощью которого React обновляет виртуальный и реальный DOM. React сравнивает текущий и новый виртуальный DOM и вносит изменения только в те узлы, которые изменились. В этом процессе важную роль играет алгоритм сравнения (diffing).

Основные этаты алгоритма Reconciliation:

1. Сравнение типов узлов. Если типы одинаковые, React проверяет пропсы и обновляет узел, если они изменились.
2. Сравнение списков. При работе со списками React использует ключи, чтобы отслеживать элементы и оптимизировать процесс обновления.

Пример использования списка с ключами:

import React, { useState } from 'react';

function TodoList() {
  const [tasks, setTasks] = useState([
    { id: 1, text: 'Learn React' },
    { id: 2, text: 'Read about Fiber' },
    { id: 3, text: 'Implement Concurrent Mode' },
  ]);

  return (
    <ul>
      {tasks.map((task) => (
        <li key={task.id}>{task.text}</li>
      ))}
    </ul>
  );
}

export default TodoList;

Ключи (key) помогают React эффективно сравнивать и обновлять список задач.

Исходный код React: Основные файлы и функции

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

ReactFiber.js

Этот файл отвечает за создание структуры фибр. Основная функция здесь — createFiber, которая создает новую фибру для узла.

function createFiber(tag, pendingProps, key, mode) {
  return {
    tag,
    key,
    pendingProps,
    // Другие свойства, такие как child, sibling, stateNode, и т.д.
  };
}

ReactDOMRoot.js

В этом файле находятся функции, связанные с управлением корневыми узлами. Важная функция — createRoot, которая создает корневую фибру и связывает ее с узлом DOM.

function createRoot(container, options) {
  // Создаем корневую фибру и возвращаем объект root
}

ReactFiberReconciler.js

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

function performUnitOfWork(unitOfWork) {
  // Обрабатываем текущую фибру и возвращаем следующую
}

Заключение

Понимание внутренней архитектуры React помогает лучше осознать, как и почему он работает так эффективно. Новая архитектура Fiber и Concurrent Mode в React 18 делает приложения более отзывчивыми и гибкими, что позволяет разработчикам создавать сложные интерфейсы, оставаясь в рамках простого декларативного подхода.

Если вы хотите углубиться в код React, рекомендуется начать с изучения структуры данных Fiber и алгоритма Reconciliation, а также экспериментов с новыми API, такими как startTransition и useTransition.

Комментарии:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *