Могу ли я использовать Angular Signals для хранения карты?

Я начинаю использовать новый API сигналов Angular. Но мне сказали, что при использовании сигналов нам нужно относиться к данным как к неизменяемым.

И я не уверен, смогу ли я сделать что-то подобное с JS Maps:

// code in my service.

// I'm using this Map to save the messages in a object and get the messages by queue name.
messages = signal(new Map<string, Object>());

queryForMessagesInQueue(queue) {
  this.httpClient.get('...').subscribe((newMessagesArray) => {
    const messages = this.messages().get(queue) || {};
    // validate if newMessages already exists in the message object
    let addedMessages = 0;
    newMessagesArray.forEach((newMsg) => {
      const messageExists = !!messages[newMsg.id]

      if (messageExists == false) {
        messages[newMsg.id] = newMsg;
        addedMessages++;
      }
    });

    if (addedMessages !== 0) {
      this.messages.update((msgMap) => msgMap.set(queue, messages));
    }
  });
}

Затем в своих компонентах я делаю что-то вроде этого:

export class MyComponent {
   private service = inject(MyService)

   messages = service.messages; // this is the service signal.
}

Правильно ли я его использую?

Можно ли использовать сигналы со структурами данных, такими как JS Maps? Будет ли корректно работать обнаружение изменений?

Заранее спасибо.

Должно работать, есть ли у вас какие-либо проблемы?

Chellappan வ 29.05.2024 18:20

@Chellappan Мое внимание привлекло то, что при использовании ChangeDetectionStrategy для OnPush обнаружение изменений не работало должным образом.

Danilo Bassi 29.05.2024 19:02

Вы можете переопределить функции равенства знаков с помощью собственного компаратора: kurtwanger40.medium.com/….

Chellappan வ 29.05.2024 19:28

@Chellappanவ это была моя оригинальная идея. Но при проверке на равенство оба значения всегда одинаковы, поскольку «старое» значение Map и «новое» значение Map являются одной и той же ссылкой.

Tortila 29.05.2024 20:08

Если возможно, можете ли вы создать пример примера в stack blitz?

Chellappan வ 30.05.2024 09:47

Вы просите меня или ОП создать? Вот stackblitz для иллюстрации.

Tortila 30.05.2024 22:55
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
6
402
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По умолчанию сигналы используют ссылочное равенство (=== сравнение). В this.messages.update вы возвращаете одно и то же Map, поэтому при проверке равенства «старое» значение Map и «новое» значение Map являются одной и той же ссылкой.

Поэтому вам нужно вернуть новый Map, чтобы ваш код работал. Кроме того, вам действительно не нужен msgMap.set(queue, messages), потому что вы уже добавили значения к messages и поэтому устанавливаете ту же ссылку messages.

Окончательный код выглядит так:

messages = signal(new Map<string, Object>());

queryForMessagesInQueue(queue) {
  this.httpClient.get('...').subscribe((newMessages) => {
    const messages = this.messages().get(queue) || {};
    const addedMessages = newMessages.filter((newMsg) => !!messages[newMsg.id]);
    if (addedMessages.length) {
      addedMessages.forEach((addedMsg) => messages[addedMsg.id] = addedMsg);
      this.message.update((msgMap) => new Map(msgMap));
    }
  });
}

Я бы также заменил Object на Record<string, Message> или индексную подпись { [messageId: string]: Message }.

Это сработало, как и ожидалось! Спасибо за предложение, исходный код немного сложнее, чем тот, о котором идет речь, я постарался максимально исключить бизнес-логику и интерфейсы.

Danilo Bassi 30.05.2024 20:51

Другие вопросы по теме