diff --git a/README.md b/README.md index 82e7d2f8..fcde5b33 100644 --- a/README.md +++ b/README.md @@ -1180,7 +1180,7 @@ class FetchMusicsTests: XCTestCase { #### [AtomScope](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/atomscope) `AtomScope` allows you to monitor changes or override atoms used in descendant views. Unlike `AtomRoot`, they affect only those in scope. -See the [Override](#override) and [Debugging](#debugging) sections for specific uses. +See the [Override Atoms](#override-atoms) and [Debugging](#debugging) sections for specific uses. ```swift AtomScope { @@ -1219,7 +1219,65 @@ struct NewsView: View { ### Techniques -#### Override +#### Scoped Atoms + +This library is designed with the shared state as a single source of truth first principle, but also the state can be scoped depending on the intended use. +Scoped atoms store their state in the nearest [AtomScope](#atomscope) in the ancestor of the view in which the atom is used, and their state is not shared outside the scope. `Scoped` is the attribute for that feature. + +```swift +struct TextInputAtom: StateAtom, Scoped Hashable { + func defaultValue(context: Context) -> String { + "" + } +} + +struct TextInputView: View { + @Watch(TextInputAtom()) + ... +} + +VStack { + // The following two TextInputView don't share TextInputAtom state. + + AtomScope { + TextInputView() + } + + AtomScope { + TextInputView() + } +} +``` + +When multiple `AtomScope`s are nested, and you want to store and share an atom state in the particular scope, it is able to define a scope ID which is to find a matching scope. + +```swift +struct TextScopeID: Hashable {} + +struct TextInputAtom: StateAtom, Scoped Hashable { + var scopeID: TextScopeID { + TextScopeID() + } + + func defaultValue(context: Context) -> String { + "" + } +} + +AtomScope(id: TextScopeID()) { + TextInputView() + + AtomScope { + // Shares TextInputAtom state with the TextInputView placed in the parent scope. + TextInputView() + } +} +``` + +This is also useful when multiple identical screens are stacked and each has isolated states such as user inputs. +Note that other atoms that depend on the scoped atom will be in a shared state and must be given `Scoped` attribute as well in order to scope them as well. + +#### Override Atoms Overriding an atom in [AtomRoot](#atomroot) or [AtomScope](#atomscope) overwrites its value when used in the descendant views, which is useful for dependency injection or swapping state in a particular view. @@ -1247,7 +1305,9 @@ var body: some { } ``` -See [Testing](#testing) section for details on dependency injection on unit tests. +Note also that overridden atoms will automatically be scoped to the `AtomScope`, but other atoms that depend on them will be in a shared state and must be given `Scoped` attribute (See also: [Scoped Atoms](#scoped-atoms)) in order to scope them as well. + +See [Testing](#testing) section for details on dependency injection on unit tests. #### Testing