<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Isoev.8</title>
    <description>The latest articles on DEV Community by Isoev.8 (@del4k1).</description>
    <link>https://dev.to/del4k1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1232585%2F4b2a5e0a-2071-4e1e-8c1c-cf15fa680f84.jpeg</url>
      <title>DEV Community: Isoev.8</title>
      <link>https://dev.to/del4k1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/del4k1"/>
    <language>en</language>
    <item>
      <title>Angular Signals + RxJS: объединяем два реактивных мира в одном стейт-менеджере</title>
      <dc:creator>Isoev.8</dc:creator>
      <pubDate>Fri, 08 Aug 2025 06:46:28 +0000</pubDate>
      <link>https://dev.to/del4k1/angular-signals-rxjs-obiediniaiem-dva-rieaktivnykh-mira-v-odnom-stieit-mieniedzhierie-4o3n</link>
      <guid>https://dev.to/del4k1/angular-signals-rxjs-obiediniaiem-dva-rieaktivnykh-mira-v-odnom-stieit-mieniedzhierie-4o3n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Signals против RxJS? Нет, вместе — они сила. Теория, практика и готовый state-manager для Angular 17 и выше&lt;br&gt;
Введение&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Введение
&lt;/h2&gt;

&lt;p&gt;Angular долгое время ассоциировался с RxJS. Даже слишком: многие разработчики ощущали, что без &lt;code&gt;Observable&lt;/code&gt; ничего не работает. Но вот в Angular 17 появляются &lt;strong&gt;Signals&lt;/strong&gt; — синхронная реактивность прямо из коробки. В 17+ — они становятся мейнстримом. Возникает вопрос: а что делать с RxJS? Выбрасывать?&lt;/p&gt;

&lt;p&gt;Signals и RxJS — не конкуренты, а два мощных инструмента для решения разных задач. И если их правильно сочетать, можно построить удобную, масштабируемую и &lt;strong&gt;эффективную архитектуру&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;В этой статье мы:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Разберёмся в различиях между Signals и RxJS&lt;/li&gt;
&lt;li&gt;Покажем, когда использовать что&lt;/li&gt;
&lt;li&gt;Сделаем свой собственный state-manager с красивым API&lt;/li&gt;
&lt;li&gt;И покажем, как всё это выглядит в реальном Angular-приложении&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Signals и RxJS — не вместо, а вместе
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Что такое Signal?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Signal&lt;/code&gt; — это реактивная, синхронная переменная. Она знает, кто её читает, и автоматически обновляет потребителей при изменении значения. Плюс: интеграция с Change Detection Angular&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {ChangeDetectionStrategy, Component, computed, effect, signal} from '@angular/core';

@Component({
  selector: 'counter',
  imports: [],
  template: `
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;Signal Counter Example&amp;lt;/h2&amp;gt;

      &amp;lt;p&amp;gt;Count: {{ count() }}&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;Doubled: {{ doubled() }}&amp;lt;/p&amp;gt;

      &amp;lt;button (click)="increment()"&amp;gt;Increment&amp;lt;/button&amp;gt;
      &amp;lt;button (click)="reset()"&amp;gt;Reset&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `,
  styles: `button { margin-right: 8px; }`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class Counter {
  // Создаем сигнал с начальным значением 0
  count = signal(0);

  // Вычисляемое значение на основе сигнала
  doubled = computed(() =&amp;gt; this.count() * 2);

  constructor() {
    // Эффект для логирования изменений
    effect(() =&amp;gt; {
      console.log(`Count changed to: ${this.count()}`);
      console.log(`Doubled value is: ${this.doubled()}`);
    });
  }

  increment() {
    // Обновляем значение сигнала
    this.count.update(current =&amp;gt; current + 1);
  }

  reset() {
    // Устанавливаем новое значение
    this.count.set(0);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Что такое RxJS?
&lt;/h3&gt;

&lt;p&gt;RxJS — это асинхронные потоки данных. Вы можете описывать сложные цепочки событий, работать с HTTP, WebSocket, таймерами, реакцией на пользовательские действия&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const clicks$ = fromEvent(button, 'click');
clicks$.pipe(throttleTime(500)).subscribe(() =&amp;gt; console.log('Click!'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Таблица различий
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Характеристика&lt;/th&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Observable (RxJS)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Push или Pull&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pull (pull-based)&lt;/td&gt;
&lt;td&gt;Push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Синхронность&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Синхронный&lt;/td&gt;
&lt;td&gt;❌ Асинхронный&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ленивая инициализация&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Нет&lt;/td&gt;
&lt;td&gt;✅ Да&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Отписка&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Не требуется&lt;/td&gt;
&lt;td&gt;✅ Требуется&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Трассировка зависимостей&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Да&lt;/td&gt;
&lt;td&gt;❌ Нет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Использование в шаблоне&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Прямо как &lt;code&gt;count()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;⚠️ Через &lt;code&gt;async&lt;/code&gt; pipe или &lt;code&gt;subscribe&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best fit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UI состояние&lt;/td&gt;
&lt;td&gt;Потоки событий, async логика&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Как они сочетаются?
&lt;/h3&gt;

&lt;p&gt;Представь, что у тебя есть UI-состояние (счётчик, фильтр, текущий пользователь) — здесь Signals чувствуют себя как дома. Но вот приходит push-уведомление, пользователь кликает слишком быстро, идёт запрос на сервер — это уже RxJS&lt;/p&gt;

&lt;p&gt;Комбо даёт следующее:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signals для UI и локального состояния&lt;/li&gt;
&lt;li&gt;RxJS для событий, побочных эффектов, async и серверного общения&lt;/li&gt;
&lt;li&gt;Мост между ними — наш state-manager&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Практика — Пишем мини state-manager
&lt;/h3&gt;

&lt;p&gt;Создать createStore, который:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;управляет состоянием&lt;/li&gt;
&lt;li&gt;позволяет "выбирать" конкретные поля через сигналы&lt;/li&gt;
&lt;li&gt;поддерживает &lt;code&gt;.effect(&lt;/code&gt;) и &lt;code&gt;.select()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;использует RxJS внутри (для расширения)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const userStore = createStore({ name: 'Anon', loggedIn: false });

// Signal-селектор
const name = userStore.select('name'); // signal&amp;lt;string&amp;gt;

// Обновление
userStore.update(state =&amp;gt; ({ ...state, name: 'Далер' }));

// RxJS эффект
userStore.effect(state$ =&amp;gt; {
  state$.pipe(
    filter(state =&amp;gt; state.loggedIn)
  ).subscribe(() =&amp;gt; console.log('User logged in!'));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Реализация createStore
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { signal, computed, effect } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

export function createStore&amp;lt;T extends Record&amp;lt;string, any&amp;gt;&amp;gt;(initial: T) {
  const subject$ = new BehaviorSubject&amp;lt;T&amp;gt;(initial);
  const stateSignal = signal&amp;lt;T&amp;gt;(initial);

  // Синхронизация сигнала с Rx
  subject$.subscribe((value) =&amp;gt; {
    stateSignal.set(value);
  });

  return {
    select&amp;lt;K extends keyof T&amp;gt;(key: K) {
      return computed(() =&amp;gt; stateSignal()[key]);
    },
    update(mutator: (prev: T) =&amp;gt; T) {
      const newValue = mutator(stateSignal());
      subject$.next(newValue);
    },
    effect(fn: (state$: Observable&amp;lt;T&amp;gt;) =&amp;gt; void) {
      fn(subject$.asObservable());
    },
    // Вдобавок:
    asSignal() {
      return stateSignal;
    },
    asObservable() {
      return subject$.asObservable();
    },
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Подводные камни
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Не стоит использовать Signals для async логики. Используй Observable + async pipe&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Signals — не замена RxJS, а его дополнение. В UI — сигналы, в бизнес-логике — потоки&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;effect() не имеет cancel/unsubscribe. В отличие от subscribe, он работает вечно&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Итог
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Signals и RxJS — это не «или-или». Это «и-и».&lt;br&gt;
Signals дают реактивность внутри UI. RxJS управляет асинхронностью и потоками.&lt;br&gt;
Вместе они позволяют писать чистые, быстрые, масштабируемые Angular-приложения&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>rxjs</category>
    </item>
  </channel>
</rss>
