onChange not work for state change by setter #2490
-
DescriptiononChange not work for state change by setter. Checklist
Expected behavioronChange should trigger when the parentNumber changed Actual behavioronChange only trigger when the parentNumber changed by ParentFeature,when ChildFeature change it's number, ParentFeature.State.number changed but onChange not fire Steps to reproducestruct ChildFeature: Reducer {
struct State: Equatable {
var number: Int
}
enum Action: Equatable {
case addNum
}
func reduce(into state: inout State, action: Action) -> Effect<Action> {
switch action {
case .addNum:
state.number += 1
return .none
}
}
}
struct ChildView: View {
let store: StoreOf<ChildFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) {viewStore in
HStack {
Text("child num: \(viewStore.number)")
Button("+") {
viewStore.send(.addNum)
}
}
}
}
}
struct ParentFeature: Reducer {
struct State: Equatable {
var parentNumber: Int
var childState: ChildFeature.State {
get {.init(number: parentNumber)}
set {parentNumber = newValue.number}
}
var latestInfo = ""
}
enum Action {
case add
case child(ChildFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: \.childState, action: /Action.child) {
ChildFeature()
}
Reduce {state, action in
switch action {
case .add:
state.parentNumber += 1
return .none
case .child:
return .none
}
}
.onChange(of: \.parentNumber) { oldValue, newValue in
Reduce { state, action in
state.latestInfo = "oldValue: \(oldValue), newValue: \(newValue)"
return .none
}
}
}
}
struct ContentView: View {
let store: StoreOf<ParentFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
VStack(alignment: .leading, spacing: 10) {
Text("latestInfo: \(viewStore.latestInfo)")
HStack {
Text("Parent num: \(viewStore.parentNumber)")
Button("+") {viewStore.send(.add)}
}
ChildView(store: self.store.scope(state: \.childState, action: { .child($0) }))
}
}
}
} The Composable Architecture version informationNo response Destination operating systemNo response Xcode version informationNo response Swift Compiler version informationNo response |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
@zpbc007 The +CombineReducers {
Scope(state: \.childState, action: /Action.child) {
ChildFeature()
}
Reduce {state, action in
switch action {
case .add:
state.parentNumber += 1
return .none
case .child:
return .none
}
}
+}
.onChange(of: \.parentNumber) { oldValue, newValue in
Reduce { state, action in
state.latestInfo = "oldValue: \(oldValue), newValue: \(newValue)"
return .none
}
} Since this isn't a bug with the library, I'm going to convert it to a discussion. |
Beta Was this translation helpful? Give feedback.
@zpbc007 The
onChange
modifier only applies to the reducer you chain onto it with. So in this case. theReduce
. If you want it to apply to the all of the child reducers, you must first combine them usingCombineReducers
(or in their own conformance/builder):