Skip to content

Example 001: Simple signal

Ниже представлен пример того, как бизнес-логика (сервис) описывается независимо от фреймворка, а React-компонент выступает лишь в роли "потребителя" данных и подписывается на изменения через метод engine.use():

tsx
import { AbstractService } from '@pravosleva/reactive-engine'
import { ReactiveEngine } from '@pravosleva/reactive-engine/react'

class Logic extends AbstractService {
  public counter = this.engine.signal<number>(0, 'example-001:signal:counter');

  public inc() {
    this.counter.value += 1
  }
}

const engine = new ReactiveEngine()

export const Example001 = () => {
  const logic = engine.inject(Logic)
  const counter = engine.use(logic.counter)

  return (
    <div>
      <div>Signal example</div>
      <code>{counter}</code>
      <div>
        <button
          onClick={() => logic.inc()}
        >+ INC</button>
      </div>
    </div>
  )
}

Использование Core-сервисов в React-окружении (Полиморфизм и DI)

Архитектура движка построена на принципах инверсии управления (IoC) и полиморфизма, что позволяет переиспользовать бизнес-логику между различными окружениями без изменений в коде самих сервисов. Класс ReactiveEngine из пакета @pravosleva/reactive-engine/react является прямым наследником базового класса ядра. Благодаря структурной типизации в TypeScript и механизмам наследования в JavaScript, расширенный инстанс движка полностью совместим с базовыми сервисами.

Когда вы импортируете AbstractService из ядра и инициализируете React-версию движка, метод .inject(Logic) корректно обрабатывает зависимость. В процессе регистрации DI-контейнер передает сервису ссылку на текущий запущенный экземпляр движка (this.engine). Таким образом, базовый сервис внутри себя незаметно для собственной логики начинает работать с расширенным React-движком. Это обеспечивает строгую изоляцию слоев: ваши сервисы остаются «чистыми» от UI-фреймворков и не содержат лишнего рантайма, но при этом без проблем реактивно связываются с компонентами через метод engine.use() на стороне React-слоя.

Как это устроено под капотом (Under the Hood)

Архитектура движка построена на принципах инверсии управления (IoC) и полиморфизма, что позволяет полностью отделить бизнес-логику приложения от UI-слоя (React) и переиспользовать сервисы в любом другом JavaScript-окружении.

Архитектура путей и полиморфизм

Класс ReactiveEngine из пакета @pravosleva/reactive-engine/react является прямым наследником базового класса ядра. Благодаря структурной типизации в TypeScript и механизмам наследования в JavaScript, расширенный инстанс движка полностью совместим с базовыми сервисами.

Когда вы импортируете AbstractService из ядра и инициализируете React-версию движка, метод .inject(Logic) корректно обрабатывает зависимость. В процессе регистрации DI-контейнер передает сервису ссылку на текущий запущенный экземпляр движка (this.engine). Таким образом, базовый сервис внутри себя незаметно для собственной логики начинает работать с расширенным React-движком.

Разделение ответственности и ограничения типов

Такой подход накладывает строгие и полезные архитектурные ограничения на уровне компиляции TypeScript:

  1. Внутри Core-сервисов (Logic): Свойство this.engine имеет тип базового класса ядра. Вы защищены от случайного вызова UI-специфичных методов (например, вы не сможете вызвать this.engine.use() внутри сервиса). Логика остается абсолютно чистой.
  2. Внутри React-компонентов (Example001): Переменная engine имеет тип расширенного класса из /react. Вам доступны как методы управления контейнером (.inject()), так и реактивные хуки для UI (.use()), которые под капотом безопасно связываются с жизненным циклом компонентов React.