⚡ Bolt: [performance improvement] Convert CartSummary to data class to prevent needless recompositions#89
Conversation
Co-authored-by: himattm <6266621+himattm@users.noreply.github.com>
|
👋 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 New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
There was a problem hiding this comment.
Code Review
This pull request converts the CartSummary class to a data class to improve Jetpack Compose stability by ensuring structural equality, and adds a corresponding entry to the project's learning documentation. Feedback includes a warning that this change will likely break existing regression tests that assert recomposition behavior. Additionally, there are suggestions to use Kotlin-specific terminology (Any.equals) in comments and to clarify in the documentation that stability requires immutable properties.
| // Making this a `data class` would fix the problem. | ||
| class CartSummary(val itemCount: Int, val totalPrice: String) | ||
| // Made this a `data class` to fix the problem by ensuring structural equality. | ||
| data class CartSummary(val itemCount: Int, val totalPrice: String) |
There was a problem hiding this comment.
While converting CartSummary to a data class correctly fixes the stability issue, this change will cause several existing regression tests to fail. Specifically, the following tests in RecompositionRegressionTest.kt currently assert that recomposition occurs on unrelated changes:\n\n- cartBanner_recomposesOnUnrelatedRefresh (line 110) asserts atLeast = 1.\n- combinedInteractions_detectsAccumulatedIssues (line 178) asserts atLeast = 3.\n\nThese tests should be updated to reflect the new stable behavior (e.g., using assertStable() or assertRecompositions(exactly = 2) for the combined case).
| // ============================================================ | ||
|
|
||
| // ISSUE: Unstable class — uses identity-based equality (Object.equals), | ||
| // FIXED: Unstable class — previously used identity-based equality (Object.equals), |
There was a problem hiding this comment.
In Kotlin, the base class is Any and the equality method is Any.equals(). Since this code is in a common module (commonMain), it is more appropriate to use Kotlin terminology rather than the Java-specific Object.equals.
| // FIXED: Unstable class — previously used identity-based equality (Object.equals), | |
| // FIXED: Unstable class — previously used identity-based equality (Any.equals), |
| @@ -0,0 +1,3 @@ | |||
| ## 2024-05-18 - Jetpack Compose Stability with Data Classes | |||
| **Learning:** Regular Kotlin classes use identity-based equality, causing Compose to falsely detect changes when instances are recreated with identical data, triggering needless recompositions. Using `data class` enables structural equality which fixes this issue. | |||
| **Action:** Always use `data class` for objects passed into Jetpack Compose UI parameters unless identity equality is intentionally required. | |||
There was a problem hiding this comment.
This guideline is helpful, but it should be clarified that data class stability in Jetpack Compose specifically requires all properties to be immutable (val). A data class with var properties is still considered unstable by the compiler unless explicitly annotated.
| **Action:** Always use `data class` for objects passed into Jetpack Compose UI parameters unless identity equality is intentionally required. | |
| **Action:** Always use data class with immutable properties (val) for objects passed into Jetpack Compose UI parameters unless identity equality is intentionally required. |
Co-authored-by: himattm <6266621+himattm@users.noreply.github.com>
💡 What: Converted
class CartSummarytodata class CartSummaryindemo-shared/src/commonMain/kotlin/demo/app/ui/ProductList.kt.🎯 Why: Regular classes use identity-based referential equality. Because the parent
ProductListScreencreated a newCartSummaryinstance on every recomposition, Compose saw this as a "changed" parameter and needlessly recomposedCartBanner, even if the underlyingitemCountandtotalPricehad not changed.data classenables structural equality (equals()compares fields), so Compose can safely skip recomposition.📊 Impact: Eliminates needless recompositions of the
CartBannercomponent, reducing UI render cycles when unrelated parts of the screen update (like the refresh button).🔬 Measurement: Run the Dejavu recomposition verification tests (
./gradlew testDebugUnitTest) and observe thatCartBannernow correctly skips recomposition.PR created automatically by Jules for task 15901048929773682013 started by @himattm