Как работает реактивность под капотом и как реализовать её?

Этот вопрос направлен на проверку понимания внутренней работы реактивности в React и того, как она реализуется на практике.

Короткий ответ

Реактивность в React работает через использование состояния и хуков, таких как useState и useEffect. Когда состояние изменяется, React автоматически инициирует перерисовку компонентов, которые зависят от этого состояния, обеспечивая согласованность между данными и интерфейсом. Реактивность достигается через механизм подписки на изменения состояния и виртуальный DOM, который минимизирует обновления реального DOM.

Длинный ответ

Для реализации реактивности на чистом JavaScript, можно использовать несколько ключевых механизмов языка. Один из популярных подходов — использование геттеров и сеттеров в сочетании с паттерном "Наблюдатель" (Observer pattern). Давайте рассмотрим, как это можно сделать на продвинутом уровне.

 

Шаг 1: Создание реактивного объекта

Для начала, создадим реактивный объект, используя ProxyProxy позволяет перехватывать и определять пользовательское поведение для основных операций (например, чтение свойства, присваивание значения и т.д.).

function reactive(target) {
  const handler = {
    get(target, property, receiver) {
      // Здесь можно добавить логику отслеживания зависимостей
      console.log(`Чтение ${property}`);
      return Reflect.get(target, property, receiver);
    },
    set(target, property, value, receiver) {
      // Здесь можно добавить логику уведомления наблюдателей
      console.log(`Установка ${property}: ${value}`);
      return Reflect.set(target, property, value, receiver);
    }
  };

  return new Proxy(target, handler);
}

const state = reactive({ count: 0 });

 

Шаг 2: Реализация паттерна "Наблюдатель"

Для уведомления подписчиков об изменениях, реализуем простую систему наблюдателей.

class Dep {
  constructor() {
    this.subscribers = new Set();
  }

  depend() {
    if (activeUpdate) {
      // Регистрируем активное обновление как зависимость
      this.subscribers.add(activeUpdate);
    }
  }

  notify() {
    // Уведомляем всех подписчиков об изменениях
    this.subscribers.forEach(sub => sub());
  }
}

let activeUpdate = null;

function autorun(update) {
  function wrappedUpdate() {
    activeUpdate = wrappedUpdate;
    update();
    activeUpdate = null;
  }

  wrappedUpdate();
}

 

Шаг 3: Связывание реактивности и наблюдателей

Теперь, когда у нас есть реактивный объект и система наблюдателей, мы можем их связать. Для этого модифицируем handler в функции reactive, чтобы использовать Dep для отслеживания зависимостей и уведомления подписчиков.

function reactive(target) {
  const depsMap = new Map();

  const handler = {
    get(target, property, receiver) {
      let dep = depsMap.get(property);
      if (!dep) {
        dep = new Dep();
        depsMap.set(property, dep);
      }

      dep.depend(); // Регистрируем зависимость

      return Reflect.get(target, property, receiver);
    },
    set(target, property, value, receiver) {
      const result = Reflect.set(target, property, value, receiver);
      let dep = depsMap.get(property);
      if (dep) {
        dep.notify(); // Уведомляем подписчиков
      }
      return result;
    }
  };

  return new Proxy(target, handler);
}

 

Шаг 4: Использование реактивного состояния

Теперь мы можем использовать нашу реактивную систему для автоматического отслеживания изменений и обновления DOM или выполнения других действий.

const state = reactive({ count: 0 });

autorun(() => {
  console.log(`Счетчик: ${state.count}`);
});

state.count++; // Автоматически вызовет логирование "Счетчик: 1"

Уровень

  • Рейтинг:

    3

  • Сложность:

    10

Навыки

  • React

    React

Ключевые слова

Подпишись на React Developer в телеграм