Manage ngrx signal store reactivity in component class

Discussão em 'Angular' iniciado por Francesco, Novembro 9, 2024.

  1. Francesco

    Francesco Guest

    After updating to Angula v17, I am rewriting a legacy component using the "classic" ngrx (observables based) with the new ngrx/signals store.

    I defined some selectors in the following fashion:

    withComputed((state) => ({
    selectOrderId: computed(() => state.orderId()),
    selectAvailableAgents: computed(() => state.availableAgents())
    ...
    })


    However, for the lazy nature of signals, if I use these selectors in the component class (not template), they will not be updated dynamically if the value changes:

    const orderId = this.ordersStore.selectOrderId();
    // orderId has only the current (at the time of invocation) value from the store


    If orderId is null, I need to invoke a service to fetch it, return the value to the component and update the store as well. Eventually, to keep this logic together, I can implement this logic inside the withMethod that returns returns the value as an observable.
    This way I would skip the selector call altogether:

    withMethods((state, ordersService = inject(OrdersService)) => ({

    fetchOrderId$: () => {
    const orderId = state.orderId();

    // If orderId available, do not call the API
    if (orderId) {
    return of(orderId);
    }

    return ordersService.getOrderId()
    .pipe(
    tapResponse({
    next: (orderId) => {
    patchState(state, { orderId })
    },
    error: (error: HttpErrorResponse) => {
    console.error("An error occurred: ", error.message);
    }
    })
    )
    }

    //In component class:

    this.orderStore.fetchOrderId$()
    .pipe(
    takeUntil(this.destroy$)
    )
    .subscribe({
    next: (orderId) => {
    // Here the logic using orderId
    }
    )}


    Using this approach, though, seems to defeat a bit the way signals work.

    In this scenario, I could think of effect() as the only way to indirectly detect when a specific part of the signal state is changed and apply specific actions to the component, for instance. But Angular docs suggest not using them to propagate the state, to avoid potential issues.

    Therefore, the resulting approach loses the peculiar indirectness provided by ngrx with observables:

    • Get the value with a selector (computed signal)
    • If value is not available in the store, invoke a service and:

      --> return it to the caller (component)
      --> update the store (patchState)

    For the cases where a value is not needed immediately, I will use rxMethods to update the state and re-execute if their params change.

    Is this a valid approach to managing selectors and values with ngrx signals or am I missing anything?

    Continue reading...

Compartilhe esta Página