ngrx / platform

Reactive State for Angular
https://ngrx.io
Other
7.96k stars 1.95k forks source link

RxMethod - Reactive Methods, in a Global Store, when / if need to unsubscribe? #4330

Closed dreamstar-enterprises closed 2 months ago

dreamstar-enterprises commented 2 months ago

Which @ngrx/* package(s) are relevant/related to the feature request?

signals, store

Information

have a ngRx signal store, it is a global singleton

Global Store

(doesn't get destroyed when component is destroyed)

export const Store = signalStore(
  {providedIn: 'root'},

  withState(initialState),

  withMethods((store) => {

    const apiService = inject(APIService);

    return {
      loadObjectByID: rxMethod<string>(
        pipe(
          filter(id => id !== undefined),
          tap(() => patchState(store, { isLoading: true, isLoaded: false })),
          take(1),
          switchMap((id) => {
            return apiService.getObject(id).pipe(
              tap({
                next: (object) => patchState(store, { object }),
                finalize: () => {
                  patchState(store, { isLoading: false, isLoaded: true });
                }
              })
            );
          })
        )
      )
    }
  })
);

Then in a component, I do the following:

Component

  protected store = inject(Store)
  protected ngOnInit(): void {
      this.Store.loadObjectByID(this.objectID) --> only method available on this is '.unsubscribe'
  }

The documentation says "By default, the rxMethod needs to be executed within an injection context. It's tied to its lifecycle and is automatically cleaned up when the injector is destroyed."

What does this mean? What is the injection context in this instance? This part of the component, protected store = inject(Store)?

Or this part of the store,

{providedIn: 'root'}?

Does this.Store.loadObjectByID(this.objectID), make a copy of the observable, or is it just a reference to what's in the store - as there is no explicit subscription.

Whatever observable is created by this.Store.loadObjectByID(this.objectID), I'm guessing it is a new one, in the component, so would need to be unsubscribed manually (when it calls the reactive method, in the store), or will it be unsubscribed automatically when the component is destroyed? Or is a copy / new instance of the observable even created at all?

Or will it persist, since the service is a global one, that only gets destroyed on a full app refresh?

Just trying to avoid memory leaks, on a component that can call a reactiveMethod in a global store multiple times, each time it's created / destroyed.

Thanks in advance.

Describe any alternatives/workarounds you're currently using

I suppose the docs could be a bit clearer on this.

I would be willing to submit a PR to fix this issue