Commit c21e66e
perf: derive accounts/evmAccounts with
## **Description**
`useAccounts` was deriving `accounts` and `evmAccounts` via `useState` +
a `useEffect` that called `getAccounts()`. This caused an extra
commit/render on every input change (account switch, account added,
etc.) because React must flush the state update separately from the
selector change.
This PR replaces that pattern with `useMemo`:
- `accounts` is now derived synchronously — no extra render
- `evmAccounts` is a second `useMemo` over `accounts`
- `ensByAccountAddress` stays as `useState` (populated asynchronously by
ENS lookups)
- ENS fetching moves to a standalone `useEffect` that depends on the
memoized `accounts`
The returned `accounts` reference is now stable across re-renders when
`internalAccounts` and the selected address are unchanged, which
prevents downstream consumers from invalidating their own memoization
unnecessarily.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: #31373
## **Manual testing steps**
N/A — internal performance change; behaviour and output are identical.
Covered by the existing unit tests plus a new referential-stability
assertion (`yarn jest
app/components/hooks/useAccounts/useAccounts.test.ts` — 9 tests, all
passing).
## **Screenshots/Recordings**
N/A — no UI change.
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> `useAccounts` is used broadly across wallet UI; the refactor should be
behavior-equivalent but changes timing of ENS fetches and loading
empty-list handling, so regressions in account lists or ENS would
surface in many flows.
>
> **Overview**
> Refactors **`useAccounts`** so `accounts` and `evmAccounts` are
**synchronously derived** with `useMemo` instead of `useState` plus a
`useEffect` that called `getAccounts()`. That removes an extra
render/commit when Redux account inputs change and keeps the
**`accounts` array reference stable** when `internalAccounts` and the
selected address are unchanged—helping consumers that memoize on
`accounts` (e.g. bridge, account selector, browser).
>
> `ensByAccountAddress` stays async `useState`; ENS reverse lookups now
run from a **dedicated `useEffect`** keyed on the memoized `accounts`
(and `fetchENS`), rather than being triggered inside account derivation.
While loading, **`isLoading` yields an empty `accounts` list** via the
memo instead of skipping updates in the effect.
>
> Adds a unit test asserting **`accounts` keeps the same reference**
across benign re-renders when inputs are unchanged.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fab91a8. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>useMemo instead of state+effect (#32721)1 parent 056a3fd commit c21e66e
2 files changed
Lines changed: 48 additions & 55 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
138 | 145 | | |
139 | 146 | | |
140 | 147 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
39 | 37 | | |
40 | 38 | | |
41 | 39 | | |
| |||
101 | 99 | | |
102 | 100 | | |
103 | 101 | | |
104 | | - | |
105 | | - | |
106 | | - | |
| 102 | + | |
| 103 | + | |
107 | 104 | | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
118 | 110 | | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
140 | 132 | | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
154 | 137 | | |
155 | 138 | | |
156 | | - | |
157 | | - | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
158 | 146 | | |
159 | | - | |
160 | | - | |
161 | 147 | | |
162 | 148 | | |
163 | 149 | | |
164 | | - | |
| 150 | + | |
165 | 151 | | |
166 | 152 | | |
167 | 153 | | |
| |||
0 commit comments