Commit c6e4302
authored
refactor: replace custom prediction hooks with team React Query hooks (MetaMask#27148)
## **Description**
Replaces the custom controller-level implementations in
`usePredictPositionsForHomepage` and `usePredictMarketsForHomepage` with
thin wrappers around the Predict team's existing React Query-backed
hooks (`usePredictPositions`, `usePredictMarketData`). This removes ~300
lines of manual caching (Map + TTL), staleness guards (`requestIdRef`),
unmount protection (`isMountedRef`), and request deduplication that
React Query handles automatically.
Key changes:
- `usePredictPositionsForHomepage` now delegates to
`usePredictPositions`, accepts an options object `{ maxPositions?,
claimable? }`, and returns `totalClaimableValue`
- `usePredictMarketsForHomepage` now delegates to `usePredictMarketData`
- `PredictionsSection` no longer manually computes `totalClaimable` or
calls `refreshClaimable` after claiming (React Query handles cache
invalidation)
- All tests updated to mock team hooks instead of
`Engine.context.PredictController`
<details>
<summary>Implementation Plan</summary>
# Refactor Predictions Homepage Hooks to Use Team Hooks
## Problem
`usePredictPositionsForHomepage` directly calls
`Engine.context.PredictController.getPositions()` and implements its own
module-level caching (Map + TTL), staleness guards (`requestIdRef`), and
unmount protection (`isMountedRef`). The Predict team already has
`usePredictPositions` which wraps the same controller call with React
Query, providing automatic caching (5s stale time), deduplication, error
handling, and optimistic polling -- all for free.
The same applies to `usePredictMarketsForHomepage` which directly calls
`PredictController.getMarkets()` with its own cache, while the team has
`usePredictMarketData` with pagination support.
## Current vs Team Hook Comparison
### Positions
| Aspect | `usePredictPositionsForHomepage` (current) |
`usePredictPositions` (team) |
|--------|-------------------------------------------|------------------------------|
| Data source | `Engine.context.PredictController.getPositions()` |
Same, via React Query `queryFn` |
| Caching | Manual Map + 60s TTL | React Query, 5s stale time |
| Staleness guard | `requestIdRef` counter | React Query built-in |
| Unmount safety | `isMountedRef` | React Query built-in |
| Filtering | `maxPositions` slice, `claimable` param | `claimable`
select filter, `marketId` filter |
| Account tracking | `selectSelectedInternalAccountFormattedAddress` |
`getEvmAccountFromSelectedAccountGroup()` |
| Return shape | `{ positions, isLoading, error, refresh }` | React
Query result (`{ data, isLoading, error, refetch }`) |
### Markets
`usePredictMarketsForHomepage` directly calls
`PredictController.getMarkets()` with manual caching, while
`usePredictMarketData` provides the same with pagination and error
handling.
## Changes
### 1. `usePredictPositionsForHomepage` -- delegate to
`usePredictPositions`
- Change signature to options object `({ maxPositions?, claimable? })`
- Remove manual state, caching, refs, and `useEffect`
- Add `totalClaimableValue` to return type
### 2. `usePredictMarketsForHomepage` -- delegate to
`usePredictMarketData`
- Remove module-level cache, manual state, refs
- Map `marketData` to `markets`, `isFetching` to `isLoading`
### 3. `PredictionsSection` -- update call sites
- Use options object for claimable call
- Remove local `totalClaimable` reduce
- Remove `refreshClaimable()` from `handleClaim` (React Query handles
it)
- Remove `refreshClaimable` from `refresh` callback
</details>
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Refs: Feedback from Predict team (Luis) about using their existing hooks
## **Manual testing steps**
```gherkin
Feature: Predictions section uses team hooks
Scenario: Positions load correctly
Given user has prediction positions
When user views the homepage Predictions section
Then positions are displayed correctly
Scenario: Trending markets load correctly
Given user has no prediction positions
When user views the homepage Predictions section
Then trending market cards are displayed in the carousel
Scenario: Claim button works
Given user has claimable positions
When user taps the Claim button
Then the claim is processed and positions update automatically
```
## **Screenshots/Recordings**
N/A -- internal refactor with no UI changes.
## **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.
## **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**
> Refactors data-fetching for the homepage Predictions section to rely
on shared React Query hooks, which may subtly change caching/refresh
behavior and when claimable amounts update. UI logic is mostly unchanged
but depends on new hook return shapes (`refetch`,
`totalClaimableValue`).
>
> **Overview**
> **Refactors the homepage Predictions section to use the Predict team’s
React Query hooks instead of controller calls + manual caching.**
`usePredictMarketsForHomepage` now wraps `usePredictMarketData` and
`usePredictPositionsForHomepage` wraps `usePredictPositions`, replacing
the old `refresh` APIs with `refetch` and adding `totalClaimableValue`
for claimable positions.
>
> `PredictionsSection` is updated to use the new hook signatures, show
the claim button based on `totalClaimableValue`, and simplify
pull-to-refresh to always `refetch` positions + markets (no separate
claimable refresh; claim no longer triggers a manual refresh).
>
> Tests are updated accordingly, including mocking
`usePredictPositions`/`usePredictMarketData` in `Homepage.test.tsx` and
adjusting section/hook tests to the new `refetch`/options-object APIs.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fa612f2. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent 0dfec6d commit c6e4302
7 files changed
Lines changed: 285 additions & 851 deletions
File tree
- app/components/Views/Homepage
- Sections/Predictions
- hooks
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
109 | 130 | | |
110 | 131 | | |
111 | 132 | | |
| |||
Lines changed: 56 additions & 78 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
| |||
51 | 50 | | |
52 | 51 | | |
53 | 52 | | |
54 | | - | |
| 53 | + | |
55 | 54 | | |
56 | 55 | | |
57 | 56 | | |
58 | 57 | | |
59 | 58 | | |
60 | | - | |
| 59 | + | |
61 | 60 | | |
62 | 61 | | |
63 | 62 | | |
| |||
140 | 139 | | |
141 | 140 | | |
142 | 141 | | |
143 | | - | |
144 | 142 | | |
145 | 143 | | |
146 | 144 | | |
| |||
165 | 163 | | |
166 | 164 | | |
167 | 165 | | |
168 | | - | |
| 166 | + | |
169 | 167 | | |
170 | 168 | | |
171 | | - | |
172 | 169 | | |
173 | | - | |
| 170 | + | |
174 | 171 | | |
175 | 172 | | |
176 | 173 | | |
177 | | - | |
| 174 | + | |
| 175 | + | |
178 | 176 | | |
179 | 177 | | |
180 | 178 | | |
| |||
214 | 212 | | |
215 | 213 | | |
216 | 214 | | |
217 | | - | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
218 | 218 | | |
219 | 219 | | |
220 | 220 | | |
221 | | - | |
| 221 | + | |
| 222 | + | |
222 | 223 | | |
223 | 224 | | |
224 | 225 | | |
| |||
236 | 237 | | |
237 | 238 | | |
238 | 239 | | |
239 | | - | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
240 | 243 | | |
241 | 244 | | |
242 | 245 | | |
243 | | - | |
| 246 | + | |
| 247 | + | |
244 | 248 | | |
245 | 249 | | |
246 | 250 | | |
| |||
280 | 284 | | |
281 | 285 | | |
282 | 286 | | |
283 | | - | |
| 287 | + | |
284 | 288 | | |
285 | 289 | | |
286 | 290 | | |
| |||
297 | 301 | | |
298 | 302 | | |
299 | 303 | | |
300 | | - | |
| 304 | + | |
301 | 305 | | |
302 | 306 | | |
303 | 307 | | |
| |||
313 | 317 | | |
314 | 318 | | |
315 | 319 | | |
316 | | - | |
| 320 | + | |
317 | 321 | | |
318 | 322 | | |
319 | 323 | | |
| |||
330 | 334 | | |
331 | 335 | | |
332 | 336 | | |
333 | | - | |
| 337 | + | |
334 | 338 | | |
335 | 339 | | |
336 | 340 | | |
| |||
346 | 350 | | |
347 | 351 | | |
348 | 352 | | |
349 | | - | |
| 353 | + | |
350 | 354 | | |
351 | 355 | | |
352 | 356 | | |
| |||
363 | 367 | | |
364 | 368 | | |
365 | 369 | | |
366 | | - | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
367 | 373 | | |
368 | 374 | | |
369 | 375 | | |
370 | | - | |
| 376 | + | |
| 377 | + | |
371 | 378 | | |
372 | 379 | | |
373 | 380 | | |
| |||
381 | 388 | | |
382 | 389 | | |
383 | 390 | | |
384 | | - | |
385 | 391 | | |
386 | | - | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
387 | 395 | | |
388 | 396 | | |
389 | 397 | | |
390 | | - | |
| 398 | + | |
| 399 | + | |
391 | 400 | | |
392 | 401 | | |
393 | 402 | | |
| |||
402 | 411 | | |
403 | 412 | | |
404 | 413 | | |
405 | | - | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
406 | 417 | | |
407 | 418 | | |
408 | 419 | | |
409 | | - | |
| 420 | + | |
| 421 | + | |
410 | 422 | | |
411 | 423 | | |
412 | 424 | | |
| |||
419 | 431 | | |
420 | 432 | | |
421 | 433 | | |
422 | | - | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
423 | 437 | | |
424 | 438 | | |
425 | 439 | | |
426 | | - | |
| 440 | + | |
| 441 | + | |
427 | 442 | | |
428 | 443 | | |
429 | 444 | | |
| |||
434 | 449 | | |
435 | 450 | | |
436 | 451 | | |
437 | | - | |
| 452 | + | |
438 | 453 | | |
439 | | - | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
440 | 457 | | |
441 | 458 | | |
442 | 459 | | |
443 | | - | |
| 460 | + | |
| 461 | + | |
444 | 462 | | |
445 | 463 | | |
446 | 464 | | |
| |||
456 | 474 | | |
457 | 475 | | |
458 | 476 | | |
459 | | - | |
460 | 477 | | |
461 | 478 | | |
462 | 479 | | |
463 | 480 | | |
464 | 481 | | |
465 | | - | |
466 | | - | |
467 | | - | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
468 | 485 | | |
469 | 486 | | |
470 | | - | |
| 487 | + | |
471 | 488 | | |
472 | 489 | | |
473 | 490 | | |
474 | | - | |
475 | | - | |
476 | | - | |
| 491 | + | |
| 492 | + | |
477 | 493 | | |
478 | 494 | | |
479 | 495 | | |
480 | 496 | | |
481 | 497 | | |
482 | 498 | | |
483 | | - | |
| 499 | + | |
484 | 500 | | |
485 | 501 | | |
486 | 502 | | |
| |||
494 | 510 | | |
495 | 511 | | |
496 | 512 | | |
497 | | - | |
498 | | - | |
499 | | - | |
500 | | - | |
501 | | - | |
502 | | - | |
503 | | - | |
504 | | - | |
505 | | - | |
506 | | - | |
507 | | - | |
508 | | - | |
509 | | - | |
510 | | - | |
511 | | - | |
512 | | - | |
513 | | - | |
514 | | - | |
515 | | - | |
516 | | - | |
517 | | - | |
518 | | - | |
519 | | - | |
520 | | - | |
521 | | - | |
522 | | - | |
523 | | - | |
524 | | - | |
525 | | - | |
526 | | - | |
527 | | - | |
528 | | - | |
529 | | - | |
530 | | - | |
531 | | - | |
532 | | - | |
533 | | - | |
534 | | - | |
535 | | - | |
536 | | - | |
| 513 | + | |
| 514 | + | |
537 | 515 | | |
538 | 516 | | |
539 | 517 | | |
0 commit comments