Skip to content

Commit 7c53812

Browse files
fix(ui): more efficient image selection updates
Only change the selection array when its contents have changed. This prevents unnecessary re-renders. For example, if the selection is currently `[image1]` and we set it again to `[image1]`, while the array contains the same objects, it is a new array. This will trigger unncessary re-renders.
1 parent 6bbaaed commit 7c53812

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { PayloadAction } from '@reduxjs/toolkit';
22
import { createSlice } from '@reduxjs/toolkit';
33
import type { PersistConfig, RootState } from 'app/store/store';
4-
import { uniqBy } from 'lodash-es';
4+
import { isEqual, uniqBy } from 'lodash-es';
55
import type { ImageDTO } from 'services/api/types';
66

77
import type { BoardId, ComparisonMode, GalleryState, GalleryView, OrderDir } from './types';
@@ -32,10 +32,54 @@ export const gallerySlice = createSlice({
3232
initialState: initialGalleryState,
3333
reducers: {
3434
imageSelected: (state, action: PayloadAction<ImageDTO | null>) => {
35-
state.selection = action.payload ? [action.payload] : [];
35+
// Let's be efficient here and not update the selection unless it has actually changed. This helps to prevent
36+
// unnecessary re-renders of the gallery.
37+
38+
const selectedImage = action.payload;
39+
40+
// If we got `null`, clear the selection
41+
if (!selectedImage) {
42+
// But only if we have images selected
43+
if (state.selection.length > 0) {
44+
state.selection = [];
45+
}
46+
return;
47+
}
48+
49+
// If we have multiple images selected, clear the selection and select the new image
50+
if (state.selection.length !== 1) {
51+
state.selection = [selectedImage];
52+
return;
53+
}
54+
55+
// If the selected image is different from the current selection, clear the selection and select the new image
56+
if (isEqual(state.selection[0], selectedImage)) {
57+
state.selection = [selectedImage];
58+
return;
59+
}
60+
61+
// Else we have the same image selected, do nothing
3662
},
3763
selectionChanged: (state, action: PayloadAction<ImageDTO[]>) => {
38-
state.selection = uniqBy(action.payload, (i) => i.image_name);
64+
// Let's be efficient here and not update the selection unless it has actually changed. This helps to prevent
65+
// unnecessary re-renders of the gallery.
66+
67+
// Remove duplicates from the selection
68+
const newSelection = uniqBy(action.payload, (i) => i.image_name);
69+
70+
// If the new selection has a different length, update the selection
71+
if (newSelection.length !== state.selection.length) {
72+
state.selection = newSelection;
73+
return;
74+
}
75+
76+
// If the new selection is different, update the selection
77+
if (!isEqual(newSelection, state.selection)) {
78+
state.selection = newSelection;
79+
return;
80+
}
81+
82+
// Else we have the same selection, do nothing
3983
},
4084
imageToCompareChanged: (state, action: PayloadAction<ImageDTO | null>) => {
4185
state.imageToCompare = action.payload;

0 commit comments

Comments
 (0)