Hello @just_some_game_dev,
I believe that starting with understanding SwiftUI is key to this question. I'd strongly encourage you to checkout the following resources in this category:
I'd defer to the Observe model data in a view section to answer much of your questions. As this section explains, breaking your view into views helps the parent views not update when a property inside a child view updates.
Use @State with @Observable to let your view observe the individual property changes rather than having the view only invalidate when the reference of the object changes.
Now for the RealityKit portion of this question, RealityKit has a RealityView(make:update:) function. The update closure will be called so that you can update the RealityView content when the view’s state changes. Don't update the view's state in this update closure. Consider not providing an update closure and instead monitoring for changes using the .onChange modifiers.
Canyon Crosser uses this approach to update the RealityView content for boolean changes, AppState changes, and changes on an entity. Introduced last year, Entity.Observable allows you to react to individual properties like the position (entity.observable.position), or whole components (entity.observable.components[HikePlaybackStateComponent.self]?.isPaused).
When you do this you are observing the component as an object, similar to @ObservableObject. Migrating from the Observable Object protocol to the Observable macro is a great article that goes over the difference between the two. In Canyon Crosser we split up hike state into three components: HikePlaybackStateComponent, HikerProgressComponent, and HikeTimingComponent. This was done, so that a view observing the paused state (PlayPauseButton) would only update when HikePlaybackStateComponent.isPaused is updated and not at every frame when HikerProgressComponent.progress is updated.
Running instruments is always advisable to understand where you might consider making additional performance updates to your application. Consider watching Optimize SwiftUI performance with Instruments to learn more about the SwiftUI instrument introduced last year. There are also a few tools that you can reach for temporarily to understand when a view updates. You can put Self._printChanges() or Self._logChanges() in the body of the view to understand why a view is changing. You can also visualize this with a flashing background color, using something like this: .background { Color(white: [1.0, 0.0].randomElement()!) }.
I hope this helps and gives you a broader understanding of how updates are triggered. Please mark this answer as accepted if this answers your questions. Is there anything that have questions about or specific details you are considering for your data model?
Thanks,
Michael