Sharing (observed) state through a computed property in combination with a didSet observer in the child causes an infinite loop #2750
Replies: 2 comments 1 reply
-
Hi @djangovanderheijden, this is not an infinite loop in the usual sense where the stack blows up. Instead, it's an infinite "render" loop, where a confluence of things is causing the view to invalidate and re-render over and over. And the reason this is happening is because when doing This isn't a bug in the library per-se. You could reproduce this problem in vanilla SwiftUI too. Sadly the fix is to be more conscience of how you are accessing inter-dependent state in this way. If you access guard self._sharedState != oldValue else {
return
} And I would say in general it's probably a good idea to only access the underscored property in Since this isn't an issue with the library I am going to convert it to a discussion. Feel free to discuss more over there. |
Beta Was this translation helpful? Give feedback.
-
I wonder if it'd be worth it to have in the migration guide a note about "infinite loops". I had encountered a scenario during the migration to 1.7 because I was sending an action to store in the initializer that was triggering mutation elsewhere, that caused the I have a feeling that there will be others that experience an infinite loop and not know what could be happening. |
Beta Was this translation helpful? Give feedback.
-
Description
Whilst converting my project to TCA 1.7 / Observation I encountered a situation that causes an infinite loop where this would previously work fine. I use a computed property on one of my parent reducers to share some state with a child reducer. The child is part of an enum of several different child types. In the child, I would respond to the state sharing through a didSet observer where I further synchronize the state change down to any children that may need access to the shared state.
A combination of the following is required for this infinite loop to happen:
@ObservableState
didSet
observer. The shared state needs to be accessed in this observer.WithPerceptionTracking
(doesn't have to be the shared state).Checklist
main
branch of this package.Expected behavior
Pre-observation, this setup works fine. The addition of
@ObservableState
andWithPerceptionTracking
to the child triggers the behavior.Actual behavior
The application hangs and the message printed in the
didSet
observer is repeated ad infinitum.Steps to reproduce
The Composable Architecture version information
1.7.1
Destination operating system
iOS 17.2.2
Xcode version information
15.2 (15C500b)
Swift Compiler version information
Beta Was this translation helpful? Give feedback.
All reactions