【问题标题】:ngrx normalized state selectorngrx 标准化状态选择器
【发布时间】:2019-05-16 10:09:29
【问题描述】:

我正在重写一个 Ionic 项目以使用 ngrx,因为它正在大量增长,我需要保持集中状态。

我已经用 ngrx 实现了它,并在 Normalizr 的帮助下使用了标准化状态。

现在我对如何将填充对象传递给哑组件有疑问:

假设我有两个接口:

interface Conversation {
    date: Date,
    lastMessage: string //this is the id of a message entity coming from normalizr
}

 interface Message {
       content: string
}

现在,当我尝试将所有对话传递给哑组件时,我正在使用这样的选择器:

getConversations() {

    //select all the conversations to have a shape of Conversation[]
    let conversations$ = this.store.select(state => Object.keys(state.entities.conversations).map( (id:string) => state.entities.conversations[id] ));

    //select all the messages in a shape { [id:string] : Message }
    let messages$ = this.store.select(state => state.entities.messages);

    return Observable.combineLatest(
      conversations$,
      messages$,
      (conversations, messages) => {
        return conversations.map(conversation => {
          return { ...conversation, lastMessage: messages[conversation.lastMessage] }

        });
      }
    )
  }

但是我返回的 Observable 不是 Conversation[] 数组,因为

return { ...conversation, lastMessage: messages[conversation.lastMessage] }

在 'lastMessage' 中放入 Message 类型的对象而不是 String。

我尝试使用对象类型的接口而不是字符串

interface Conversation {
       date: Date,
       lastMessage: Message
    }

但是我不能使用像

这样的选择器
this.store.select(state => state.entities.messages[conversation.lastMessage]

因为它不再是字符串了。

我怎样才能做到这一点?

谢谢

【问题讨论】:

    标签: ngrx normalizr


    【解决方案1】:

    这个问题的简短回答如下:

    你需要从最后一条消息中选择content属性,如:

    return { ...conversation, lastMessage: messages[conversation.lastMessage].content }
    

    更长的答案:

    选择器也可以实现同样的效果,与 RxJS 操作符相比,它的好处是可重用性更高。

    选择器是一个纯函数,它将状态作为参数,并且 返回商店状态的一部分。而不是仅仅返回 存储在存储中的数据,选择器可以根据 可用的数据。这允许您只存储基本信息,保持 状态树尽可能紧凑。另一个重要的部分是 选择器可以组合,即:一个选择器可以取一个或 多个其他选择器作为其输入。

    例如:

    // getters
    export const selectUser = (state: AppState) => state.selectedUser;
    export const selectAllBooks = (state: AppState) => state.allBooks;
    
    // create a selector with `createSelector` and use the getters above
    export const selectVisibleBooks = createSelector(
      selectUser,
      selectAllBooks,
      (selectedUser: User, allBooks: Books[]) => {
        if (selectedUser && allBooks) {
          return allBooks.filter((book: Book) => book.userId === selectedUser.id);
        } else {
          return allBooks;
        }
      }
    );
    

    在你的组件中选择选择书籍,你可以这样做:

    this.books = this.store.pipe(select(selectVisibleBooks));
    

    更多信息:

    【讨论】:

    • 您好,感谢您的回复。我的问题更多关于打字稿的打字。规范化实体有一个字符串(它是相关对象的 id),而不是里面的完整对象。因此,例如,我用字符串字段而不是 Message 编写了所有实体。但是当我使用选择器来检索填充的对话以传递给哑组件时,它不再是 Conversation 类型,因为在 lastMessage 字段中不再有字符串,而是 Message 类型。
    猜你喜欢
    • 1970-01-01
    • 2019-03-18
    • 2018-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多