Okto
Okto

Reputation: 367

Angular Signals - Using mutate() vs. Using forEach() Reactivity

Considering the following Angular Signals example, I'm somewhat confused about when I should use the Signal API, like mutate() and update(), when the Array API, such as forEach, is sufficient to trigger reactivity and update the UI/template? What is the difference here? Used Angular Version: 16.0.1

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  template: `
    {{usersList() | json}}
  `,
})
export class App {
  usersList: Signal<any> = inject(UserService).getUsersList();
  constructor() {
 
  }
}

bootstrapApplication(App);

@Injectable({
  providedIn: 'root',
})
export class UserService {
  private users = signal([
    { id: 1, name: 'Peter', country: 'USA' },
    { id: 2, name: 'Party Boy', country: 'USA' },
    { id: 3, name: 'John Connor', country: 'USA' },
  ]);

  constructor() {
      window.setTimeout(()=>{
        this.changeUsersListWithoutMutate();
      }, 3000),

      window.setTimeout(()=>{
        this.changeUsersListWithMutate();
      }, 5000)
  }

  changeUsersListWithoutMutate(){
    this.users().forEach((item) => {
      if (item.id === 1) {
        item.name = "changeListWithoutMutate";
      }
    });
  }

  changeUsersListWithMutate(){
    this.users.mutate((data) => {
      data.forEach((item) => {
        if (item.id === 1) {
          item.name = "changeListWithMutate";
        }
      });
    });
  }

  getUsersList() {
    return this.users;
  }
}

Upvotes: 1

Views: 2284

Answers (1)

Matthieu Riegler
Matthieu Riegler

Reputation: 55554

What you are observing in your example is standard change detection because you rely on setTimeout().

setTimeout is one of the APIs patched by zone.js, this means everytime it's called Angular will fire a change detection cycle and refresh your DOM. Since the value wraped by the signal has been changed (no matter which way), the new value will appear in the DOM.

That being said, back to the signal basics:

In changeUsersListWithoutMutate, you're not updating the signal because you're reading its value and changing its nested values. The signal itself has no way to know it has been updated.

This is why changeUsersListWithMutate is the way to go. You're explicitly telling the signal that you are updating it's value and the signal will fire the change detection.

Let me know if something isn't clear in my answer.

Upvotes: 7

Related Questions