В ngrx (с ngrx / effects), как получить идентификатор вновь созданного элемента?

Допустим, вы создаете новую книгу, отправив действие CREATE_BOOK из компонента BookComponent. По сути, мы обрабатываем http-сохранение, а после этого передаем созданную книгу редуктору с помощью действия CREATE_BOOK_SUCCESS. Все идет нормально.

Но как получить идентификатор вновь созданной книги в компоненте BookComponent, который вызвал действие CREATE_BOOK? Я могу думать только об обходных путях:

  • Сохраните созданную книгу в состоянии, в поле lastCreatedBook. Это не кажется масштабируемым, если у меня много разных предметов. Кроме того, мне придется очистить это поле, когда компонент будет уничтожен.
  • получить полный список книг в BookComponent. Последняя - это созданная Книга.
  • Не используйте ngrx / effects. Просто вызовите метод BookService.create () и подпишитесь на него. Отправьте оттуда действие CREATE_BOOK_SUCCESS. Но тогда зачем вообще использовать эффекты?

person David Bulté    schedule 22.07.2018    source источник
comment
Не уверен, как выглядит ваш дизайн пользовательского интерфейса - обычно после нажатия кнопки «Добавить» можно вернуться на страницу списка. В список обычно добавляется недавно добавленная книга.   -  person Wand Maker    schedule 22.07.2018
comment
Пользовательский интерфейс был бы чем-то вроде страницы, на которой можно было бы дать свою любимую книгу во всплывающем окне. Во всплывающем окне предлагается выбрать существующую книгу или создать новую. После создания новой страницы на исходной странице должна быть ссылка на новую книгу.   -  person David Bulté    schedule 22.07.2018
comment
В сценарии, который вы описываете, как можно узнать, что это за созданная книга (скажем, чтобы выделить ее). Это та же проблема, не так ли?   -  person David Bulté    schedule 22.07.2018
comment
Понятно. Если вы хотите выделить недавно добавленную книгу в список книг - тогда да, вам нужен способ пометить эту книгу как новую - если вы можете добавить created_time в книгу, то это может помочь вам выбрать последнюю. . Ваш второй вариант или какой-то его вариант - лучший вариант.   -  person Wand Maker    schedule 22.07.2018


Ответы (2)


Я тоже столкнулся с этой ситуацией, и, на мой взгляд, у вас есть 2 варианта:

  • первый и, безусловно, самый простой, вы создаете идентификатор непосредственно во фронтенде, используя библиотеку UUID, но, возможно, ваши идентификаторы генерируются на бэкэнде, и вы не можете этого сделать
  • второй вариант, немного менее вперед, но он тоже отлично работает:

Сгенерируйте идентификатор и передайте его в полезной нагрузке действия (в дополнение к вашей текущей полезной нагрузке, если необходимо). Вы можете назвать это, например, actionId.

Исходя из вашего эффекта, когда вы сопоставляете действие CREATE_BOOK_SUCCESS, также передайте этот идентификатор, к которому у вас есть доступ! (потому что мы находимся в той части кода, которая обрабатывает действие CREATE_BOOK).

Из (умного) компонента вы можете подписаться на действия, как и в своих эффектах! И так можно сделать что-то вроде этого:

class MyComponent {
  // ...

  createBook(book: Book) {
    // first, generate a unique ID to track the action
    // you can call directly the uuid function or even better create
    // a uuidService that you inject but for simplicity here I'm not doing it
    const actionId: string = uuid();

    // then watch for an action of type CREATE_BOOK_SUCCESS with that ID
    this.actions.pipe(
      ofType<BooksActions.CreateBookSuccess>(BooksActions.CREATE_BOOK_SUCCESS),
      filter(({payload}) => payload.actionId === actionId),
      first(),
      tap(({payload}) => {
        // do what you want here
        // you've got access to the payload of the CREATE_BOOK_SUCCESS action where
        // you have the book returned from the backend (I think)
      })
    );

    // finally, dispatch the action
    // it's important to do it after you've subscribed to actions otherwise it might happen
    // too fast and you wouldn't get the notification
    this.actions.dispatch(new BooksActions.CreateBook({ ...book, actionId }));
  }

  // ...
}

Обратите внимание, что я использую здесь first при подписке на действие, поэтому даже если вы добавите 10 книг очень быстро, у вас будет 10 разных подписок, что совершенно нормально.

person maxime1992    schedule 22.07.2018
comment
Хороший! Мне было интересно, могу ли я подписаться на действия в самом компоненте (я имею в виду, я знал, что мы можем, но я никогда не видел этого в примерах или около того, так что, может быть, это считается плохой практикой?). Однако, используя first (), мы должны быть в безопасности. Спасибо! - person David Bulté; 23.07.2018
comment
Подписки останутся открытыми, если вы не добьетесь успеха. Думаю, в этом случае это не большая проблема, но ее следует учитывать. Может быть исправлено с помощью большего количества строк кода, в которых действия _FAILED выполняются в acocunt. - person SchreiberLex; 23.10.2019
comment
Правильно, это также должно иметь takeUntil(componentDestroyed$) - person maxime1992; 23.10.2019

Вы не можете напрямую сообщить компоненту созданный идентификатор, потому что вы должны следовать однонаправленному потоку данных redux.

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

Если вы хотите выделить созданную книгу где-нибудь в списке, вы можете реализовать trackBy функцию из директиве *ngFor и создайте анимацию для вновь созданного элемента.

Дополнительные сведения об использовании эффектов см. На странице Начните использовать для этого ngrx / effects

person timdeschryver    schedule 22.07.2018
comment
OP спросил how would one get the ID of the newly created Book in the BookComponent that spawned the CREATE_BOOK action, использование ngFor ему в этом не поможет. - person maxime1992; 22.07.2018
comment
Правильно, но насколько я понимаю, он просто хочет выделить созданный элемент. - person timdeschryver; 23.07.2018