-
-
Notifications
You must be signed in to change notification settings - Fork 17
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Checklist
- Reviewed the README and documentation.
- Checked existing issues & PRs to ensure not duplicated.
Description
Currently, atoms in a scope are released when there are no active subscriptions, even if the scope itself still exists. This proposal suggests adding a mechanism to retain atoms within a scope until the scope is explicitly destroyed, which is particularly useful for state preservation in lazy-loaded containers (e.g., scrollable lists).
Example Use Case
In a LazyVStack
with reusable cells (like ScopeCellView
below), we want to preserve fetched data even when cells scroll offscreen. Atoms should only be released when their parent container (AtomScope
) is dismissed:
struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Scope test") {
ScopeTestView()
}
}
}
}
}
// Parent container
struct ScopeTestView: View {
var body: some View {
AtomScope(id: "lazyContainer") {
ScrollView {
LazyVStack {
ForEach(0..<20) { num in
ScopeCellView(num: num) // Cells may be reused/destroyed
}
}
}
}
}
}
// Child view
struct ScopeCellView: View {
let num: Int
@ViewContext
private var viewContext
private var value: AsyncPhase<Int, Error> {
viewContext.watch(NumberTestAtom(number: num))
}
var body: some View {
HStack {
Text(num.description)
Spacer()
switch value {
case .suspending:
ProgressView()
case .success(let value):
Text(value.description)
case .failure(let error):
Text(error.localizedDescription)
}
}
}
}
// Atom definition (current workaround)
struct NumberTestAtom: AsyncPhaseAtom, Scoped, KeepAlive {
let number: Int
func value(context: Context) async throws -> Int {
try await Task.sleep(nanoseconds: 3_000_000_000) // Costly fetch
return number
}
var scopeID: String { "lazyContainer" } // Scoped to parent container
}
Alternative Solution
No response
Proposed Solution
- Maybe we should introduce a
LifecycleScope
for Atom lifetime management, since the existingAtomScope
is used for data isolation. - introduce a new Atom attribute named
KeepAliveInScopes
protocol KeepAliveInScopes {
var aliveInScopes: [LifecycleScopeID] { get }
}
Motivation & Context
- Performance Optimization: Avoid redundant async operations when revisiting scoped elements (e.g., list items).
- Expected Behavior Alignment: Scoped atoms should logically belong to their parent scope's lifecycle, not individual view subscriptions.
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request