RxResource Streams 내부에서 TAP () 쓰기를 중지한 이유

작성자

카테고리:

← 피드로
DEV Community · Yasin Demir · 2026-07-08 개발(SW)
Cover image for Why I Stopped Writing tap() Inside rxResource Streams

Yasin Demir

There’s a pattern I see a lot in Angular codebases that adopted Signals early: a developer discovers rxResource, loves that it handles loading and error state automatically, and then immediately reaches for tap() to write a signal inside the stream.

private readonly resource = rxResource({
    params: () => this.paramsSignal(),
    stream: ({ params }) =>
        this.api.fetch(params).pipe(
            tap(data => this.sideSignal.set(data.meta)) // 💥
        )
});

Enter fullscreen mode Exit fullscreen mode

This looks harmless. It runs in development without complaint in zone-based Angular. Then you enable zoneless, or Angular tightens its reactive graph enforcement, and you get NG0600: Writing to signals is not allowed in a reactive context.

The rxResource stream runs inside Angular’s reactive scheduler. Signal writes there aren’t just discouraged. They’re illegal by design. The scheduler assumes computed signals and reactive contexts are read-only during evaluation. A write mid-computation breaks the glitch-free guarantee Angular’s signal graph is built on.

The fix I landed on: make the stream return everything it needs to return, as a single typed value.

interface ResourceValue {
    readonly sections: Section[];
    readonly meta: Meta;
}

private readonly resource = rxResource<ResourceValue, Params>({
    stream: ({ params }) =>
        this.api.fetch(params).pipe(
            map(data => ({
                sections: transform(data),
                meta: data.meta
            }))
        )
});

Enter fullscreen mode Exit fullscreen mode

No tap. No side signal. Everything the rest of the store needs lives in resource.value() and can be read via computed.

The lesson isn’t “don’t use tap”. The lesson is that rxResource has a contract: it is a read primitive. Its stream is for fetching and transforming. If you’re writing signals inside it, you’re treating it as a command bus, and that’s a different tool.

Originally published on ysndmr.com.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다