如何将一对多字段作为Redux-orm中的数组



我有以下使用redux-orm的聊天应用程序的模型。每个Conversation包含许多Messages,但是一条消息只能属于一个Conversation

export class Message extends Model {
  static modelName = 'Message';
  static fields = {
    id: attr(),
    text: attr(),
    created: attr(),
    from: fk('User'),
    conversation: fk('Conversation', 'messages')
  };
}
export class Conversation extends Model {
  static modelName = 'Conversation';
  static fields =  {
    id: attr(),
    created: attr(),
  };
}

我正在使用以下选择器获取与他们各自的消息的对话列表。

export const getConversations = createSelector(
  getOrm,
  createOrmSelector(orm, session =>  {
    return session.Conversation
      .all()
      .toModelArray()
  })
);

问题?每个Conversation实例的messages属性是QuerySet,而不是Array,这使得通过Ti组件时很难处理。

这是我尝试过的解决方案:

  1. 映射每个Conversation模型的messages属性,返回使用messages.all().toModelArray()Messages数组。即使我尝试克隆对象。

  2. ,这也给了我错误 Can't mutate a reverse many-to-one relation
  3. 创建一个全新的普通旧JavaScript对象并复制所有属性,然后为messages设置正确的值。这有效,但是创建所有这些新对象似乎是频繁变化的应用程序上的巨大性能猪。

我应该如何在这里实现目标?

您应该能够做类似的事情:

return session.Conversation.all().toModelArray()
  .map(c => ({
    ...c.ref,
    messages: c.messages.toRefArray()
  }))

在您的选择器中。如果那不起作用,则可能需要包含更多细节。您不会免费获得与初始toModelArray的关系,因此您需要"查询"它们才能在选择器中使用它们。

通常,我不仅会为这些实体倾倒整个商店内容,而且我会改进组件实际要求的内容:

import { pick } from 'lodash/fp'
// ...
const refineConversation = c => ({
  ...pick([ 'id', 'updatedAt' ], c),
  messages: c.messages.toRefArray().map(refineMessages)
})
const refineMessages = m => ({
  ...pick([ 'id', 'author', 'text', 'updatedAt' ], m)
})
// ...
return session.Conversation
  .all()
  .toModelArray()
  .map(refineConversation)

虽然只能从组件上的商店中扔一个对象引用,但该对象上有很多东西,您的组件可能不需要渲染。如果这些情况有所改变,则组件具有重新渲染的,您的选择器无法使用其记忆的数据。

请记住,当您使用对象扩展(或Object.assign)时,您就会创建浅副本。是的,有一个成本,但是超过第一个嵌套的任何东西都是使用参考,因此您不会克隆整个过程。选择器的使用应保护您不必在mapStateToProps中做太多工作(在使用该数据的第一个渲染之后)。

重要的是要与国家管理层做出好选择,但是真正的性能命中可能来自其他来源(不必要的渲染,等待API互动等)。

最新更新