From 54597f0fcadd29dc148daff61c5f27e0ec328c8d Mon Sep 17 00:00:00 2001 From: cryptotavares Date: Tue, 6 Jan 2026 14:36:03 +0000 Subject: [PATCH 1/3] perf: memoize getNumberOfAllUnapprovedTransactionsAndMessages selector --- ui/selectors/selectors.js | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 6f0f8a6f9120..d84bb9c37c0d 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -2472,19 +2472,32 @@ export function getShowRecoveryPhraseReminder(state) { * @param state - Redux state object. * @returns Number of unapproved transactions */ -export function getNumberOfAllUnapprovedTransactionsAndMessages(state) { - const unapprovedTxs = getUnapprovedTransactions(state); - - const allUnapprovedMessages = { - ...unapprovedTxs, - ...state.metamask.unapprovedDecryptMsgs, - ...state.metamask.unapprovedPersonalMsgs, - ...state.metamask.unapprovedEncryptionPublicKeyMsgs, - ...state.metamask.unapprovedTypedMessages, - }; - const numUnapprovedMessages = Object.keys(allUnapprovedMessages).length; - return numUnapprovedMessages; -} +export const getNumberOfAllUnapprovedTransactionsAndMessages = + createDeepEqualSelector( + [ + getUnapprovedTransactions, + (state) => state.metamask.unapprovedDecryptMsgs, + (state) => state.metamask.unapprovedPersonalMsgs, + (state) => state.metamask.unapprovedEncryptionPublicKeyMsgs, + (state) => state.metamask.unapprovedTypedMessages, + ], + ( + unapprovedTxs, + unapprovedDecryptMsgs, + unapprovedPersonalMsgs, + unapprovedEncryptionPublicKeyMsgs, + unapprovedTypedMessages, + ) => { + const allUnapprovedMessages = { + ...unapprovedTxs, + ...unapprovedDecryptMsgs, + ...unapprovedPersonalMsgs, + ...unapprovedEncryptionPublicKeyMsgs, + ...unapprovedTypedMessages, + }; + return Object.keys(allUnapprovedMessages).length; + }, + ); export const getCurrentNetwork = createDeepEqualSelector( getNetworkConfigurationsByChainId, From 9c8454544ce87326d480097221e127e608a51109 Mon Sep 17 00:00:00 2001 From: cryptotavares Date: Tue, 6 Jan 2026 23:05:19 +0000 Subject: [PATCH 2/3] perf: use createShallowEqualSelector for better performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shallow equality O(n) is sufficient since inputs come from Immer-managed state with stable references, avoiding expensive deep equality O(n×d). --- ui/selectors/selectors.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index d84bb9c37c0d..ac01de5d4559 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -136,6 +136,7 @@ import { MULTICHAIN_NETWORK_TO_ASSET_TYPES } from '../../shared/constants/multic import { hasTransactionData } from '../../shared/modules/transaction.utils'; import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; import { createDeepEqualSelector } from '../../shared/modules/selectors/util'; +import { createShallowEqualSelector } from '../../shared/modules/selectors/selector-creators'; import { isSnapIgnoredInProd } from '../helpers/utils/snaps'; import { EMPTY_ARRAY, EMPTY_OBJECT } from './shared'; import { @@ -2473,7 +2474,7 @@ export function getShowRecoveryPhraseReminder(state) { * @returns Number of unapproved transactions */ export const getNumberOfAllUnapprovedTransactionsAndMessages = - createDeepEqualSelector( + createShallowEqualSelector( [ getUnapprovedTransactions, (state) => state.metamask.unapprovedDecryptMsgs, From 4a406e7d692de288e4439312cc2c061d68f8a7d7 Mon Sep 17 00:00:00 2001 From: cryptotavares Date: Wed, 7 Jan 2026 14:21:02 +0000 Subject: [PATCH 3/3] perf: optimize selector with direct count summation - Switch to createSelector (reference equality) since Redux/Immer provides stable input references - Sum Object.keys lengths directly instead of spreading objects - Avoids O(N) memory allocation and potential ID collision issues --- ui/selectors/selectors.js | 48 +++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index ac01de5d4559..1eb409d88a09 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -136,7 +136,6 @@ import { MULTICHAIN_NETWORK_TO_ASSET_TYPES } from '../../shared/constants/multic import { hasTransactionData } from '../../shared/modules/transaction.utils'; import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; import { createDeepEqualSelector } from '../../shared/modules/selectors/util'; -import { createShallowEqualSelector } from '../../shared/modules/selectors/selector-creators'; import { isSnapIgnoredInProd } from '../helpers/utils/snaps'; import { EMPTY_ARRAY, EMPTY_OBJECT } from './shared'; import { @@ -2473,32 +2472,27 @@ export function getShowRecoveryPhraseReminder(state) { * @param state - Redux state object. * @returns Number of unapproved transactions */ -export const getNumberOfAllUnapprovedTransactionsAndMessages = - createShallowEqualSelector( - [ - getUnapprovedTransactions, - (state) => state.metamask.unapprovedDecryptMsgs, - (state) => state.metamask.unapprovedPersonalMsgs, - (state) => state.metamask.unapprovedEncryptionPublicKeyMsgs, - (state) => state.metamask.unapprovedTypedMessages, - ], - ( - unapprovedTxs, - unapprovedDecryptMsgs, - unapprovedPersonalMsgs, - unapprovedEncryptionPublicKeyMsgs, - unapprovedTypedMessages, - ) => { - const allUnapprovedMessages = { - ...unapprovedTxs, - ...unapprovedDecryptMsgs, - ...unapprovedPersonalMsgs, - ...unapprovedEncryptionPublicKeyMsgs, - ...unapprovedTypedMessages, - }; - return Object.keys(allUnapprovedMessages).length; - }, - ); +export const getNumberOfAllUnapprovedTransactionsAndMessages = createSelector( + [ + getUnapprovedTransactions, + (state) => state.metamask.unapprovedDecryptMsgs, + (state) => state.metamask.unapprovedPersonalMsgs, + (state) => state.metamask.unapprovedEncryptionPublicKeyMsgs, + (state) => state.metamask.unapprovedTypedMessages, + ], + ( + unapprovedTxs, + unapprovedDecryptMsgs, + unapprovedPersonalMsgs, + unapprovedEncryptionPublicKeyMsgs, + unapprovedTypedMessages, + ) => + Object.keys(unapprovedTxs ?? {}).length + + Object.keys(unapprovedDecryptMsgs ?? {}).length + + Object.keys(unapprovedPersonalMsgs ?? {}).length + + Object.keys(unapprovedEncryptionPublicKeyMsgs ?? {}).length + + Object.keys(unapprovedTypedMessages ?? {}).length, +); export const getCurrentNetwork = createDeepEqualSelector( getNetworkConfigurationsByChainId,