The only way to actually change state in a Store is by committing a mutation. Define a function that returns Mutation object. That expresses that function is Mutation
<aside> ⚠️ Mutation does NOT allow to run asynchronous operation.
</aside>
Mutation does NOT allow to run asynchronous operation.
struct MyState {
var todos: [TODO] = []
}
class MyStore: Store<MyState, Never> {
func addNewTodo(title: String) {
commit { (state: inout InoutRef<MyState>) in
state.todos.append(Todo(title: title, hasCompleted: false))
}
}
}
<aside> 💡 If the commit has no modifications, Store skips the mutation.
</aside>
let store = MyStore()
store.addNewTodo(title: "Create SwiftUI App")
print(store.state.todos)
// store.state.todos => [Todo(title: "Create SwiftUI App", hasCompleted: false)]
Committing multiple mutations in a short time might decrease performance. Because the subscribers around the store derive a state many times.
Like this,
class MyStore: Store<MyState, Never> {
func myMutation() {
if ... {
commit {
...
}
// emits updated event
}
if ... {
commit {
...
}
// emits updated event
}
if ... {
commit {
...
}
// emits updated event
}
}
}
To keep better performance, we need to keep using fewer commits in a short time.
We have 2 ways.
commit
commit
provides InoutRef<State>
, that can detect how the wrapped state will change.
If there is no change, commit
does nothing and no emitting the events from the Store.
However, you should attention commit
is atomically operation which means, the Store getting lock while committing.