New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add "Distinct" property wrapper #200
Conversation
Hi @haeseoklee, can you please explain what exactly would be the difference between |
Pulse responds whenever a value is injected, but Distinct responds whenever a value changes. Pulseclass TestReactor: Reactor {
enum Action {
case showAlert(message: String?)
}
enum Mutation {
case setAlertMessage(String?)
}
struct State {
@Pulse var alertMessage: String?
}
let initialState = State()
func mutate(action: Action) -> Observable<Mutation> {
switch action {
case let .showAlert(message):
return Observable.just(Mutation.setAlertMessage(message))
}
}
func reduce(state: State, mutation: Mutation) -> State {
var newState = state
switch mutation {
case let .setAlertMessage(alertMessage):
newState.alertMessage = alertMessage
}
return newState
}
} var receivedAlertMessages: [String] = []
reactor.pulse(\.$alertMessage)
.compactMap { $0 }
.subscribe(onNext: { alertMessage in
receivedAlertMessages.append(alertMessage)
})
.disposed(by: disposeBag)
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
print(receivedAlertMessages) // ["3", "3", "3", "3", "3"] Distinctclass TestReactor: Reactor {
enum Action {
case showAlert(message: String?)
}
enum Mutation {
case setAlertMessage(String?)
}
struct State {
@Distinct var alertMessage: String?
}
let initialState = State()
func mutate(action: Action) -> Observable<Mutation> {
switch action {
case let .showAlert(message):
return Observable.just(Mutation.setAlertMessage(message))
}
}
func reduce(state: State, mutation: Mutation) -> State {
var newState = state
switch mutation {
case let .setAlertMessage(alertMessage):
newState.alertMessage = alertMessage
}
return newState
}
} var receivedAlertMessages: [String] = []
reactor.state(\.$alertMessage)
.compactMap { $0 }
.subscribe(onNext: { alertMessage in
receivedAlertMessages.append(alertMessage)
})
.disposed(by: disposeBag)
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
reactor.action.onNext(.showAlert(message: "3"))
print(receivedAlertMessages) // ["3"] |
It's certainly a good attempt, but in this case, I think the existing method of adding |
Thanks for your comment! @leedh2004 |
I thought that most people were more familiar with the traditional way, and traditional way(adding |
Thank you for your new proposal! reactor.state.map(\.foo)
. distinctUntilChanged() I think most people are more familiar with the existing way. reactor.state.map(\.foo)
reactor.state(\.foo)
reactor.state.map(\.foo)
. distinctUntilChanged()
reactor.state(\.foo)
. distinctUntilChanged() When a new state function is created, the existing state has the same name. |
@OhKanghoon However, if you feel unfamiliar with this method and have the potential to confuse existing code, I think it may do more harm than good. I don't know if it could be improved for the better (renaming or something...), but as you said, I'm cautious and worried that people will have to learn new features. In that regard, I will take time to reconsider my proposal. :) |
Motivation
Observer subscribing to the reactor state causes unnecessary view re-rendering when the
distinctUntilChanged
operator is not applied.Therefore, in order to prevent unnecessary re-rendering, this problem must be prevented during the property declaration phase. This idea was inspired by
Pulse
. Thanks to @tokijhFeature
Therefore, introduce a property wrapper called
Distinct
.Property wrapped in
Distinct
can be obtained throughstate
method andkeyPath
. At this time, it is executed only when the value changes, and the above-mentioned problems can be solved. This method simplifies state subscriptions and is more intuitive.In order to apply
Distinct
property wrappers, the type of property must be hashable.Here's an improved code.