1

我有以下用于聊天应用程序的模型,使用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()
  })
);

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

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

  1. messages将每个模型的属性映射到withConversation的数组。即使我尝试克隆对象,这也给了我错误。Messagesmessages.all().toModelArray()Can't mutate a reverse many-to-one relation

  2. 创建一个全新的普通旧 JavaScript 对象并复制所有属性,然后为messages. 这行得通,但是创建所有这些新对象对于状态频繁更改的应用程序来说似乎是一个巨大的性能消耗。

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

4

1 回答 1

3

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

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

在您的选择器中。如果这不起作用,您可能需要包含更多详细信息。您不会免费获得与 initial 的关系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 交互等)。

于 2017-12-21T04:49:51.893 回答