Skip to content

Fix: initialize currentHighlights @State from highlights parameter for first-render correctness#1

Open
R2kashyap wants to merge 1 commit into
melihcolpan:mainfrom
R2kashyap:main
Open

Fix: initialize currentHighlights @State from highlights parameter for first-render correctness#1
R2kashyap wants to merge 1 commit into
melihcolpan:mainfrom
R2kashyap:main

Conversation

@R2kashyap

Copy link
Copy Markdown

Summary

Fixes a bug where AnimatedBodyContainer doesn't render highlights on first appearance. Users see an empty body view until they interact with it (tap a muscle, toggle front/back), which forces re-instantiation and a fresh render.

The Bug

AnimatedBodyContainer.currentHighlights is a @State property initialized to an empty dictionary:

@State private var currentHighlights: [Muscle: MuscleHighlight] = [:]

The rendering flow on first appearance:

  1. SwiftUI creates AnimatedBodyContainer with highlights parameter containing heatmap data
  2. @State currentHighlights initializes to [:] (empty)
  3. body is evaluated — Canvas draws using blendedHighlights(progress: 1.0) which returns currentHighlights (empty)
  4. View appears on screen showing no highlights
  5. .onAppear fires, sets currentHighlights = highlights
  6. Canvas does not automatically redraw from that @State change
  7. User sees empty body until interaction forces re-render

The Fix

Initialize @State directly from the highlights parameter using the standard SwiftUI pattern for external initial values:

init(..., highlights: [Muscle: MuscleHighlight], ...) {
    // ... other assignments
    self._currentHighlights = State(initialValue: highlights)
}

Now the first Canvas draw has correct data. The .onAppear is no longer needed (removed). The .onChange(of: highlights) path is preserved for subsequent updates when highlights change after initial render.

How to Reproduce

// In a parent view that loads data asynchronously:
BodyView(gender: .male, side: .front)
    .heatmap([
        MuscleIntensity(muscle: .chest, intensity: 0.8),
        MuscleIntensity(muscle: .biceps, intensity: 0.5)
    ])
    .animated(duration: 0.3)

Before fix: Body renders without colors on first appearance. Toggle front/back to see colors.

After fix: Colors render immediately on first appearance.

Changes

  • Sources/MuscleMap/Views/AnimatedBodyView.swift
    • Added explicit init that initializes _currentHighlights via State(initialValue: highlights)
    • Removed .onAppear { currentHighlights = highlights } (no longer needed)
    • Changed @State private var currentHighlights: [Muscle: MuscleHighlight] = [:] to remove default initializer

Testing

  • Verified in production app with heatmap data present on first render
  • Verified .onChange(of: highlights) still works for subsequent updates
  • Verified front/back toggle still animates correctly

The @State currentHighlights was initialized to empty [:], causing the first Canvas render to draw without highlights. .onAppear would then set currentHighlights = highlights, but Canvas would not re-draw automatically from that @State change. Users saw an empty body view until they interacted with it (toggle front/back, tap a muscle) which forced re-instantiation.

This fix initializes @State from the highlights parameter directly via State(initialValue:), so the first Canvas draw uses the correct data. .onChange(of: highlights) is preserved for subsequent updates.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant