2017-12-20 11 views
1

redux-ormを使用してチャットアプリケーション用の次のモデルを用意しました。各Conversationは多くのMessages含まれていますが、一つのメッセージは、単一のConversationに属することができます:私は、それぞれのメッセージとの会話のリストを取得するには、次のセレクタを使用していredux-ormの配列として1対多のフィールドを取得する方法

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プロパティは、Arrayではなく、QuerySetであり、tiコンポーネントを渡すときに対処することが困難です。

  1. messages.all().toModelArray()Messagesの配列に戻されたすべてのConversationモデルのmessagesプロパティのマッピング:

    は、ここで私が試したソリューションです。これにより、オブジェクトをクローンしたときでも、エラーCan't mutate a reverse many-to-one relationが返されました。

  2. 完全に新しいプレーンな古いJavaScriptオブジェクトを作成し、すべてのプロパティをコピーしてから、messagesの正しい値を設定します。これはうまくいきましたが、これらの新しいオブジェクトをすべて作成することは、頻繁な状態変更を伴うアプリケーションでは、大きなパフォーマンスのように思えます。

ここで目標を達成するにはどうすればよいですか?

答えて

2

あなたはに似て何かを行うことができるはずである:あなたのセレクタに

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)を使用している場合、浅いコピーを作成していることに注意してください。はい、コストはありますが、ネストの最初のレベルを超えたものは参照を使用しているので、not cloning the whole thingです。セレクタを使用すると、mapStateToProps(あのデータで最初にレンダリングされた後に)で多すぎる作業をしなくても済むはずです。

状態管理で適切な選択を行うことが重要ですが、実際のパフォーマンスのヒットは他のソースから来る可能性があります(不要なレンダリング、APIのやりとりを待つなど)。

+0

私はすべて時期尚早な最適化に反対していますが、私のセレクタでこれらの新しいオブジェクトをすべてビルドしないと、パフォーマンスが大幅に低下しますか?特に 'Conversation'に複数の外部キーを追加した場合(特定の' sender'オブジェクトと 'attachment'' one-to-many配列を追加した場合) –

+0

Redux-ORMには、再選択の 'createSelector'のカスタマイズされたバージョンが組み込まれています。 READMEには、その使用例があります:https://github.com/tommikaikkonen/redux-orm#use-with-react。そうすれば、あなたの「出力セレクタ」は、それらの「データベーステーブル」が更新されたときにのみ再計算されます。 – markerikson

+2

@markeriksonはもちろん正しいですが、私はあなたがすでにそれを使用しているのを見ています。しかし、私はパフォーマンスをより詳しく説明する答えを広げます。短い答え:それはまだセレクターのパフォーマンスを心配しないでください。 –

関連する問題