Search code examples
javascriptangulartypescriptobjectngrx

Save state theme on ngrx


There is a theme switcher that affects the visual appearance of the app. Naturally, it does not return anything, but only boolean values.

I have a service from which a button in the header works. Actually here it is:

@Injectable({
  providedIn: 'root',
})
export class ThemeService {
  public _darkTheme$$: Observable<boolean> = this.store.select(selectChanges);

  constructor(private store: Store) {}

  setTheme(theme: boolean) {
    this.store.dispatch(changeTheme({ change: theme }));
  }
}

next - header

  toggleTheme(theme: boolean): void {
    this.themeService.setTheme(theme);
  }

html:

  <mat-slide-toggle
     [checked]="themeService._darkTheme$$ | async"
     (change)="toggleTheme($event.checked)"
  ></mat-slide-toggle>

In the storage itself, the data is being replaced. However, when creating a module effect, I catch a bunch of errors

actually the effect itself for the storage:


@Injectable()
export class ThemeEffect {
  constructor(private actions$: Actions, private themeService: ThemeService) {}

  // @ts-ignore
  toggleTheme$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(changeTheme),
      mergeMap((change: { change: boolean }) => {
        return this.themeService.setTheme(change.change);
      }),
      // map(
      //   (i) => this.themeService.setTheme(i.change),
      //   catchError((err) => throwError(err)),
      // ),
    );
  });
}


Solution

  • An effect should always return an action (because these are dispatched to the store). From the looks of it themeService.setTheme does not return an action, but is just something that needs to be invoked. This means you have to define the effect as a non-dispatching effect.

    https://ngrx.io/guide/effects/lifecycle#non-dispatching-effects

    @Injectable()
    export class ThemeEffect {
      constructor(private actions$: Actions, private themeService: ThemeService) {}
    
      // @ts-ignore
      toggleTheme$ = createEffect(() => {
        return this.actions$.pipe(
          ofType(changeTheme),
          mergeMap((change: { change: boolean }) => {
            return this.themeService.setTheme(change.change);
          }),
          // map(
          //   (i) => this.themeService.setTheme(i.change),
          //   catchError((err) => throwError(err)),
          // ),
        );
      // 👇
      }, { dispatch: false});
    }
    
    

    Side-note: Please provide the errors when you create an issue.