ngrx / platform

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

Writing to signals is not allowed in a `computed` or an `effect` by default. Use `allowSignalWrites` in the `CreateEffectOptions` to enable this inside effects. #4466

Closed Bryan-Herrera-DEV closed 1 month ago

Bryan-Herrera-DEV commented 1 month ago

Which @ngrx/* package(s) are the source of the bug?

effects

Minimal reproduction of the bug/regression with instructions

<input
      hlmInput
      id="correo"
      formControlName="correo"
      class="col-span-3"
      autocomplete="off"
      autocapitalize="off"
      list="emails-list"
      (ngModelChange)="buscarUsuariosKeycloak($event)"
    />
    <datalist id="emails-list">
      <option *ngFor="let searched of searchResults" [value]="searched.mail">
    </datalist>
private readonly _rawFilterInput = signal<string>('');
  private readonly _emailFilter = toSignal(
    toObservable(this._rawFilterInput).pipe(debounceTime(300))
  );

  constructor(
    private route: ActivatedRoute,
    private fb: FormBuilder,
    private store: Store,
    private actions$: Actions,
    private router: Router,
  ) {
    this.initForm();

    effect(() => {
      const value = this._emailFilter();
      if (value) {
        this.store.dispatch(searchUsers({ query: value }));
      }
    });
  }

Expected behavior

Without problem

Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)

"dependencies": { "@angular/animations": "^18.1.0", "@angular/cdk": "18.0.0", "@angular/common": "^18.1.0", "@angular/compiler": "^18.1.0", "@angular/core": "^18.1.0", "@angular/forms": "^18.1.0", "@angular/platform-browser": "^18.1.0", "@angular/platform-browser-dynamic": "^18.1.0", "@angular/router": "^18.1.0", "@ng-icons/core": "^25.1.0", "@ng-icons/lucide": "^26.3.0", "@ngrx/effects": "^18.0.1", "@ngrx/store": "^18.0.1", "@ngrx/store-devtools": "^18.0.1", "@ngxpert/cmdk": "^1.0.0", "@spartan-ng/ui-accordion-brain": "0.0.1-alpha.352", "@spartan-ng/ui-alertdialog-brain": "0.0.1-alpha.352", "@spartan-ng/ui-avatar-brain": "0.0.1-alpha.352", "@spartan-ng/ui-checkbox-brain": "0.0.1-alpha.352", "@spartan-ng/ui-collapsible-brain": "0.0.1-alpha.352", "@spartan-ng/ui-command-brain": "0.0.1-alpha.352", "@spartan-ng/ui-core": "^0.0.1-alpha.352", "@spartan-ng/ui-dialog-brain": "0.0.1-alpha.352", "@spartan-ng/ui-hovercard-brain": "0.0.1-alpha.352", "@spartan-ng/ui-label-brain": "0.0.1-alpha.352", "@spartan-ng/ui-menu-brain": "0.0.1-alpha.352", "@spartan-ng/ui-popover-brain": "0.0.1-alpha.352", "@spartan-ng/ui-progress-brain": "0.0.1-alpha.352", "@spartan-ng/ui-radiogroup-brain": "0.0.1-alpha.352", "@spartan-ng/ui-select-brain": "0.0.1-alpha.352", "@spartan-ng/ui-separator-brain": "0.0.1-alpha.352", "@spartan-ng/ui-sheet-brain": "0.0.1-alpha.352", "@spartan-ng/ui-switch-brain": "0.0.1-alpha.352", "@spartan-ng/ui-table-brain": "0.0.1-alpha.352", "@spartan-ng/ui-tabs-brain": "0.0.1-alpha.352", "@spartan-ng/ui-toggle-brain": "0.0.1-alpha.352", "@spartan-ng/ui-tooltip-brain": "0.0.1-alpha.352", "angular-oauth2-oidc": "^17.0.2", "class-variance-authority": "^0.6.0", "clsx": "^1.2.1", "embla-carousel-angular": "^14.0.0", "keycloak-angular": "^16.0.1", "keycloak-js": "^25.0.2", "ngx-scrollbar": "^13.0.1", "ngx-sonner": "^2.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" }, "devDependencies": { "@angular-devkit/build-angular": "^18.1.0", "@angular/cli": "^18.1.0", "@angular/compiler-cli": "^18.1.0", "@chromatic-com/storybook": "^1.6.1", "@compodoc/compodoc": "^1.1.25", "@spartan-ng/cli": "^0.0.1-alpha.360", "@storybook/addon-docs": "^8.2.6", "@storybook/addon-essentials": "^8.2.6", "@storybook/addon-interactions": "^8.2.6", "@storybook/addon-links": "^8.2.6", "@storybook/addon-onboarding": "^8.2.6", "@storybook/angular": "^8.2.6", "@storybook/blocks": "^8.2.6", "@storybook/test": "^8.2.6", "@types/jasmine": "~5.1.0", "autoprefixer": "^10.4.19", "jasmine-core": "~5.1.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", "postcss": "^8.4.39", "storybook": "^8.2.6", "tailwind-merge": "^2.2.0", "tailwindcss": "^3.4.6", "tailwindcss-animate": "^1.0.6", "typescript": "~5.5.2" }

Other information

No response

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

rainerhahnekamp commented 1 month ago

@Bryan-Herrera-DEV, use the untracked That's a typical pattern for your issue.

effect(() => {
  const value = this._emailFilter();

  untracked(() => {
    if (value) {
      this.store.dispatch(searchUsers({ query: value }));
    }
  })
});

You will encounter it often...and not just when working with NgRx.

markostanimirovic commented 1 month ago

This is expected behavior. By default, a signal cannot be updated within the effect. In the case of NgRx Store, the global state is stored in a signal and dispatched action updates the state.

As the error message said, you can use { allowSignalWrites: true }. Another option is to use untracked.


We're using issues for bug reports and feature requests. For questions, join our Discord server, use GitHub discussions or Stackoverflow.

Bryan-Herrera-DEV commented 1 month ago
untracked(() => {

This work for me, thx <3