MetaMask / MetaMask/metamask-mobile

Memoize selectCustomNetworkConfigurationsByCaipChainId filter result

Open Beginner friendly
#31,348 1 comment 0 reactions 0 assignees View on GitHub
area-performance Sev3 size-XS ta-triaged team-mobile-ux team-networks
Dominant language
TypeScript
Stars
3k
Forks
1.7k
Avg merge
1d 14h
Merged PRs (30d)
669

Description

> **Performance audit finding** · Severity: **Medium** · Effort: Easy · Fix risk: Simple · Test safety net: Partial
> Owner: `@MetaMask/mobile-core-ux (suggested)`
> File: `app/selectors/networkController.ts:274`

### What is this about?

`selectCustomNetworkConfigurationsByCaipChainId` is a plain `createSelector` whose result function returns `Object.values(...).filter(...)`, building a new array every recompute. Its input `selectNetworkConfigurationsByCaipChainId` is a plain `createSelector` that builds a fresh object (via `getNetworkConfigurationsByCaipChainId` spreads) whenever either network slice changes, so this selector reruns and yields a new array on any network-slice mutation.

**Why it matters**

Custom network lists feed network management/picker UI. A new array reference forces consumers to re-render even when the custom networks are unchanged.

### Scenario

N/A — see Technical Details.

### Design

N/A — internal performance change; no UI/design impact.

### Technical Details

**Evidence**

`app/selectors/networkController.ts:274`
```ts
export const selectCustomNetworkConfigurationsByCaipChainId = createSelector(
selectNetworkConfigurationsByCaipChainId,
(networkConfigurationsByChainId) =>
Object.values(networkConfigurationsByChainId).filter(
(networkConfiguration) =>
(networkConfiguration.chainId.startsWith('0x') &&
!POPULAR_NETWORK_CHAIN_IDS.has(networkConfiguration.chainId as Hex)) ||
NON_EVM_TESTNET_IDS.includes(networkConfiguration.caipChainId),
),
);
```

**Fix**

Switch to `createDeepEqualSelector` so the filtered array is referentially stable when contents are unchanged.

### Threat Modeling Framework

N/A — performance-only change; behavior is preserved, no new data flow / trust boundary / attack surface.

### Acceptance Criteria

- `app/selectors/networkController.test.ts:177` asserts values but not referential stability. Add a test asserting `toBe` across two equal-content states. Profiler: confirm network-management consumers stop re-rendering on unrelated network-state changes.

### References

- File: `app/selectors/networkController.ts:274`
- Source: MetaMask Mobile performance audit — finding `selector-custom-network-configs-by-caip`
- Owner (CODEOWNERS / best-effort): @MetaMask/mobile-core-ux (suggested)
- Status: **UNVALIDATED**

Contributor guide

Open the contributing guide

Research direction

Start with app/selectors/networkController.ts:274 and inspect how selectCustomNetworkConfigurationsByCaipChainId derives its result. Then read app/selectors/networkController.test.ts:177 and add coverage for referential stability across equal-content states. Done means the selector preserves the array reference when contents are unchanged and the selector tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend, performance
Issue type
Refactor
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.