Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

⚡ Bolt: Memoize derived state in TournamentCenter - #13

Closed
ereezyy wants to merge 1 commit into
mainfrom
bolt-memoize-tournament-center-17796171807431594123
Closed

⚡ Bolt: Memoize derived state in TournamentCenter#13
ereezyy wants to merge 1 commit into
mainfrom
bolt-memoize-tournament-center-17796171807431594123

Conversation

@ereezyy

@ereezyy ereezyy commented Mar 4, 2026

Copy link
Copy Markdown
Owner

💡 What: Wrapped playerHorses, filteredTournaments, and tournamentWins in React.useMemo hooks in TournamentCenter.tsx.
🎯 Why: These derived states were previously calculated on every render. As the horses and tournaments arrays grow, this causes unnecessary O(N) operations which impact rendering performance.
📊 Impact: Reduces redundant re-calculations on re-renders by caching the filtered results unless dependencies change. This improves the rendering speed of the TournamentCenter component.
🔬 Measurement: React DevTools Profiler should show reduced render times for TournamentCenter when changing tabs or interacting with the UI, as the arrays are not re-filtered.


PR created automatically by Jules for task 17796171807431594123 started by @ereezyy

Summary by Sourcery

Enhancements:

  • Memoize player horse filtering, tournament filtering, and tournament win count calculations in TournamentCenter to avoid repeated O(N) recomputations on each render.

Wrapped `playerHorses`, `filteredTournaments`, and `tournamentWins` in `useMemo` hooks to prevent unnecessary filtering operations on every render.
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@sourcery-ai

sourcery-ai Bot commented Mar 4, 2026

Copy link
Copy Markdown

Reviewer's Guide

Memoizes derived data in TournamentCenter by wrapping expensive filters and computed values in React.useMemo to avoid recalculations on every render and improves rendering performance.

Sequence diagram for memoized derived state in TournamentCenter renders

sequenceDiagram
  participant React
  participant TournamentCenter
  participant useMemo_playerHorses as useMemo_playerHorses
  participant useMemo_filteredTournaments as useMemo_filteredTournaments
  participant useMemo_tournamentWins as useMemo_tournamentWins

  React->>TournamentCenter: render(horses, tournaments, player, currentTab)
  TournamentCenter->>useMemo_playerHorses: compute or return cache
  useMemo_playerHorses-->>TournamentCenter: playerHorses

  TournamentCenter->>useMemo_filteredTournaments: compute or return cache
  useMemo_filteredTournaments-->>TournamentCenter: filteredTournaments

  TournamentCenter->>useMemo_tournamentWins: compute or return cache
  useMemo_tournamentWins-->>TournamentCenter: tournamentWins

  TournamentCenter-->>React: render UI with memoized values

  rect rgb(230,230,250)
    Note over React,TournamentCenter: Subsequent render with same dependencies
    React->>TournamentCenter: re-render (no change to horses, tournaments, player, currentTab)
    TournamentCenter->>useMemo_playerHorses: dependencies unchanged
    useMemo_playerHorses-->>TournamentCenter: cached playerHorses

    TournamentCenter->>useMemo_filteredTournaments: dependencies unchanged
    useMemo_filteredTournaments-->>TournamentCenter: cached filteredTournaments

    TournamentCenter->>useMemo_tournamentWins: dependencies unchanged
    useMemo_tournamentWins-->>TournamentCenter: cached tournamentWins

    TournamentCenter-->>React: render UI without re-filtering arrays
  end

  rect rgb(220,255,220)
    Note over React,TournamentCenter: Render where a dependency changes
    React->>TournamentCenter: re-render (currentTab changed)
    TournamentCenter->>useMemo_filteredTournaments: dependencies changed
    useMemo_filteredTournaments-->>TournamentCenter: recomputed filteredTournaments
  end
Loading

Flow diagram for memoized data derivation in TournamentCenter

flowchart LR
  subgraph Inputs
    A[horses array]
    B[tournaments array]
    C[player object]
    D[currentTab state]
  end

  subgraph Derived_with_useMemo
    E[playerHorses useMemo]
    F[filteredTournaments useMemo]
    G[tournamentWins useMemo]
  end

  subgraph UI_Render
    H["My Horses list"]
    I["Tournament tabs (Active / Upcoming / History)"]
    J["Tournament Wins stat"]
  end

  A --> E
  C --> E

  B --> F
  D --> F

  C --> G

  E --> H
  F --> I
  G --> J

  classDef memo fill:#e0f7fa,stroke:#00838f,stroke-width:1px;
  class E,F,G memo;
Loading

File-Level Changes

Change Details Files
Memoize derived collections and counts in TournamentCenter to avoid recomputation on every render.
  • Wrap playerHorses computation in useMemo with dependencies on horses and the player wallet address.
  • Wrap filteredTournaments computation in useMemo keyed by tournaments and the current tab, preserving the existing filter logic for statuses.
  • Extract the tournament wins calculation into a tournamentWins variable memoized with useMemo based on player stats achievements and update the JSX to use this memoized value.
src/components/TournamentCenter.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • For the playerHorses memo, consider destructuring player (e.g. const walletAddress = player?.walletAddress;) and using walletAddress in the dependency array to avoid depending on the whole player object implicitly and to keep react-hooks/exhaustive-deps happier.
  • The tournamentWins memo currently depends on player?.stats.achievements, which may change identity frequently; if possible, derive a stable reference (or compute this closer to where player is updated) so the memoization can actually avoid recalculation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- For the `playerHorses` memo, consider destructuring `player` (e.g. `const walletAddress = player?.walletAddress;`) and using `walletAddress` in the dependency array to avoid depending on the whole `player` object implicitly and to keep `react-hooks/exhaustive-deps` happier.
- The `tournamentWins` memo currently depends on `player?.stats.achievements`, which may change identity frequently; if possible, derive a stable reference (or compute this closer to where `player` is updated) so the memoization can actually avoid recalculation.

## Individual Comments

### Comment 1
<location path="src/components/TournamentCenter.tsx" line_range="232-234" />
<code_context>
+    [tournaments, currentTab]
+  );
+
+  const tournamentWins = useMemo(() =>
+    player?.stats.achievements.filter(a => a.name.includes('Tournament')).length || 0,
+    [player?.stats.achievements]
+  );

</code_context>
<issue_to_address>
**issue (bug_risk):** Use safer optional chaining and align the dependency array to avoid potential runtime errors.

`player?.stats.achievements` can still throw if `stats` is `undefined`/`null`: `player?.stats` may be `undefined`, and then accessing `.achievements` will fail. This affects both the memo body and the dependency array. Consider:

```ts
const tournamentWins = useMemo(
  () => player?.stats?.achievements?.filter(a => a.name.includes('Tournament')).length ?? 0,
  [player?.stats?.achievements]
);
```

This handles partially populated `player` objects and keeps the dependency array consistent with the computed value.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +232 to +234
const tournamentWins = useMemo(() =>
player?.stats.achievements.filter(a => a.name.includes('Tournament')).length || 0,
[player?.stats.achievements]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Use safer optional chaining and align the dependency array to avoid potential runtime errors.

player?.stats.achievements can still throw if stats is undefined/null: player?.stats may be undefined, and then accessing .achievements will fail. This affects both the memo body and the dependency array. Consider:

const tournamentWins = useMemo(
  () => player?.stats?.achievements?.filter(a => a.name.includes('Tournament')).length ?? 0,
  [player?.stats?.achievements]
);

This handles partially populated player objects and keeps the dependency array consistent with the computed value.

@ereezyy ereezyy closed this Jul 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant