@@ -71,10 +71,35 @@ const initState = ({
71
71
export class AttachmentManager {
72
72
readonly state : StateStore < AttachmentManagerState > ;
73
73
readonly composer : MessageComposer ;
74
+ private attachmentsByIdGetterCache : {
75
+ attachmentsById : Record < string , LocalAttachment > ;
76
+ attachments : LocalAttachment [ ] ;
77
+ } ;
74
78
75
79
constructor ( { composer, message } : AttachmentManagerOptions ) {
76
80
this . composer = composer ;
77
81
this . state = new StateStore < AttachmentManagerState > ( initState ( { message } ) ) ;
82
+ this . attachmentsByIdGetterCache = { attachmentsById : { } , attachments : [ ] } ;
83
+ }
84
+
85
+ get attachmentsById ( ) {
86
+ const { attachments } = this . state . getLatestValue ( ) ;
87
+
88
+ if ( attachments !== this . attachmentsByIdGetterCache . attachments ) {
89
+ this . attachmentsByIdGetterCache . attachments = attachments ;
90
+ this . attachmentsByIdGetterCache . attachmentsById = attachments . reduce <
91
+ Record < string , LocalAttachment >
92
+ > ( ( newAttachmentsById , attachment ) => {
93
+ // should never happen but does not hurt to check
94
+ if ( ! attachment . localMetadata . id ) return newAttachmentsById ;
95
+
96
+ newAttachmentsById [ attachment . localMetadata . id ] ??= attachment ;
97
+
98
+ return newAttachmentsById ;
99
+ } , { } ) ;
100
+ }
101
+
102
+ return this . attachmentsByIdGetterCache . attachmentsById ;
78
103
}
79
104
80
105
get client ( ) {
@@ -176,44 +201,47 @@ export class AttachmentManager {
176
201
this . state . next ( initState ( { message } ) ) ;
177
202
} ;
178
203
179
- getAttachmentIndex = ( localId : string ) =>
180
- this . attachments . findIndex (
181
- ( attachment ) =>
182
- attachment . localMetadata . id && localId === attachment . localMetadata ?. id ,
183
- ) ;
204
+ getAttachmentIndex = ( localId : string ) => {
205
+ const attachmentsById = this . attachmentsById ;
206
+
207
+ return this . attachments . indexOf ( attachmentsById [ localId ] ) ;
208
+ } ;
184
209
185
210
upsertAttachments = ( attachmentsToUpsert : LocalAttachment [ ] ) => {
186
211
if ( ! attachmentsToUpsert . length ) return ;
187
- const stateAttachments = this . attachments ;
188
- const attachments = [ ...this . attachments ] ;
189
- attachmentsToUpsert . forEach ( ( upsertedAttachment ) => {
190
- const attachmentIndex = this . getAttachmentIndex (
191
- upsertedAttachment . localMetadata . id ,
192
- ) ;
193
212
194
- if ( attachmentIndex === - 1 ) {
195
- const localAttachment = ensureIsLocalAttachment ( upsertedAttachment ) ;
196
- if ( localAttachment ) attachments . push ( localAttachment ) ;
213
+ const currentAttachments = this . attachments ;
214
+ const newAttachments = [ ...currentAttachments ] ;
215
+
216
+ attachmentsToUpsert . forEach ( ( attachment ) => {
217
+ const targetAttachmentIndex = this . getAttachmentIndex ( attachment . localMetadata ?. id ) ;
218
+
219
+ if ( targetAttachmentIndex < 0 ) {
220
+ const localAttachment = ensureIsLocalAttachment ( attachment ) ;
221
+ if ( localAttachment ) newAttachments . push ( localAttachment ) ;
197
222
} else {
223
+ // do not re-organize newAttachments array otherwise indexing would no longer work
224
+ // replace in place only with the attachments with the same id's
198
225
const merged = mergeWithDiff < LocalAttachment > (
199
- stateAttachments [ attachmentIndex ] ?? { } ,
200
- upsertedAttachment ,
226
+ currentAttachments [ targetAttachmentIndex ] ,
227
+ attachment ,
201
228
) ;
202
229
const updatesOnMerge = merged . diff && Object . keys ( merged . diff . children ) . length ;
203
230
if ( updatesOnMerge ) {
204
231
const localAttachment = ensureIsLocalAttachment ( merged . result ) ;
205
- if ( localAttachment ) attachments . splice ( attachmentIndex , 1 , localAttachment ) ;
232
+ if ( localAttachment )
233
+ newAttachments . splice ( targetAttachmentIndex , 1 , localAttachment ) ;
206
234
}
207
235
}
208
236
} ) ;
209
237
210
- this . state . partialNext ( { attachments } ) ;
238
+ this . state . partialNext ( { attachments : newAttachments } ) ;
211
239
} ;
212
240
213
241
removeAttachments = ( localAttachmentIds : string [ ] ) => {
214
242
this . state . partialNext ( {
215
243
attachments : this . attachments . filter (
216
- ( att ) => ! localAttachmentIds . includes ( att . localMetadata ?. id ) ,
244
+ ( attachment ) => ! localAttachmentIds . includes ( attachment . localMetadata ?. id ) ,
217
245
) ,
218
246
} ) ;
219
247
} ;
0 commit comments