Skip to main content

rxState

The functional way to create and configure an RxState instance. rxState() is a wrapper around the class-based RxState service that binds its lifecycle to the current injection context; the instance is destroyed automatically when the host component/directive/service is destroyed. It is the modern default for local reactive state; the class API is the legacy surface.

Every signature below is source-derived (package 21.1.1).

When to use RxState (and when signals are enough): for local component state prefer Angular's signal() / computed(). rxState() earns its place for global/shared state, complex derived state, and async-heavy orchestration. See Reactive state: global vs local, RxState + signals.

Import

import { rxState } from '@rx-angular/state';

Signature

rxState has four overloads: no-arg, setup function, options, and setup function + options:

export function rxState<State extends object>(): RxState<State>;
export function rxState<State extends object>(setupFn: RxStateSetupFn<State>): RxState<State>;
export function rxState<State extends object>(options: RxStateOptions): RxState<State>;
export function rxState<State extends object>(setupFn: RxStateSetupFn<State>, options: RxStateOptions): RxState<State>;
ParamTypeMeaning
setupFnRxStateSetupFn<State>Optional. Runs once on creation with a subset of the state handle (connect, set, get, select, setAccumulator) so you can seed initial state and wire connections in one place.
optionsRxStateOptionsOptional. Provide an explicit injector so rxState() can be called outside an injection context.
returnsRxState<State>The functional state handle (see below).

Must be called within an injection context, unless an injector is supplied via RxStateOptions.

Returned handle: RxState<State>

The functional handle is a Pick of the class RxState service exposing 10 members:

// Illustrative shape only — see the note below.
type RxState<T extends object> = Pick<LegacyState<T>, 'get' | 'select' | 'connect' | 'set' | '$' | 'setAccumulator' | 'signal' | 'computed' | 'computedFrom' | 'asReadOnly'>;

This Pick type shows the shape of the handle; it is not directly importable. import { RxState } from '@rx-angular/state' resolves to the class-based RxState service, not this type. If you need a named type for the handle, capture it via ReturnType<typeof rxState>.

MemberKindMeaning
$Observable<State>The raw, unmodified state observable; not shared, distinct, or replayed.
getmethodRead a one-shot, non-reactive snapshot; creates no dependency and never re-runs on change, so never call it inside computed()/state.computed() or a template binding. Use signal/select/computed for reactive reads. See RxState#get.
setmethodWrite a Partial<State>, a projection function, or a single-key value. See RxState#set.
connectmethodMerge an Observable/Signal source into state (8 overloads). See RxState#connect.
selectmethodRead state reactively as a cached, distinct Observable. See RxState#select.
signalmethodRead a single key as a Signal<State[Key]>, the signals-first template surface. See RxState#signal.
computedmethodDerive a Signal from multiple keys. See RxState#computed.
computedFrommethodDerive a Signal from state via RxJS operators. See RxState#computedFrom.
asReadOnlymethodReturn a read-only view exposing only get/select/computed/signal.
setAccumulatormethod@deprecated: customize the accumulation function. Prefer provideRxStateConfig(withAccumulatorFn(...)).

The functional handle does not expose hold(). For side effects, use rxEffects().register(...) instead (the rxEffects Reference is authored later in this Phase-C run).

RxStateSetupFn<State>

The setup function receives a 5-member subset of the handle:

export type RxStateSetupFn<State extends object> = (rxState: Pick<RxState<State>, 'connect' | 'set' | 'get' | 'select' | 'setAccumulator'>) => void;

RxStateOptions

type RxStateOptions = {
injector?: Injector;
};

RxStateOptions is an internal type: it is not re-exported from @rx-angular/state, so it cannot be imported by name. The signatures above use it only to describe the options object's shape — pass a matching object literal ({ injector }) directly.

FieldTypeMeaning
injectorInjectorOptional. Explicit injector used to bind the instance's lifecycle, allowing rxState() to be called outside an injection context.

Minimal example

import { Component, inject } from '@angular/core';
import { rxState } from '@rx-angular/state';

@Component({
selector: 'app-movie-list',
template: `
@for (movie of movies(); track movie.id) {
<app-movie [movie]="movie" />
}
`,
})
export class MovieListComponent {
private readonly movieService = inject(MovieService);

private readonly state = rxState<{ movies: Movie[] }>(({ set, connect }) => {
set({ movies: [] });
connect('movies', this.movieService.movies$);
});

// signals-first template surface
readonly movies = this.state.signal('movies');
}

Signal interop

rxState() bridges reactive sources into signals for the template:

  • state.signal('key'): read one key as a Signal.
  • state.computed((s) => s.a + s.b): derive a Signal from multiple keys.
  • state.computedFrom(map(...), filter(...)): derive a Signal through RxJS operators.
  • connect('key', someSignal): write a Signal source into state.

Prefer these signal accessors over $ / select() for template bindings on modern, zoneless apps.

Configuration

rxState() reads its accumulator and scheduler from DI. Provide them with provideRxStateConfig:

import { provideRxStateConfig, withAccumulatorFn, withScheduler } from '@rx-angular/state';
import { asapScheduler } from 'rxjs';

providers: [
provideRxStateConfig(
withAccumulatorFn((state, slice) => ({ ...state, ...slice })),
withScheduler(asapScheduler),
),
];

See also