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
@connect discussion and implementation #400
Comments
This looks interesting, but I think I need more background info :) I'm not fluent in the JS origins of ReSwift and don't know what the Implementation wise, the When you have to specify the mapping in store.subscribe(self) {
$0.skipRepeats({ [weak self] (oldState: AppState, newState: AppState) -> Bool in
SomeComponent.Props(items: newState.feedState.items,
datasource: newState.feedState.feeds[id] ?? [])
})
} And then make the Disclaimer: I don't subscribe views or view controllers in any of my apps. I use Presenters for this. My presenters do the state-to-view-model-mapping; your suggestion is shorter, but then I'd have to write the conversion code from state to |
I'm using ReRxSwift in my latest project, the bindings layer for RxSwift and ReSwift, similar to React Redux for React and Redux. |
@Dimillian the code you shared is a bit uncanny to code that we've put together across ReSwift + ReKotlin. There's some differences, but I think we try to should share a bit more.
Overall I think we've taken a much more strict approach in that even a component does not have access to the store, and is managed by, you guessed it, a componentManager. View controller / fragment owns componentManager, componentManager manages component state subscriptions. This way, on This was an approach that felt like it would allow a better separation of views from screens, but it does not mean I'm attached to it. |
@Dimillian I should also mention an advantage of removing the store from components is that they become completely autonomous units of code, that can be tested as such. |
@jimisaacs Uncanny indeed, I took a look at ReRxSwift and it's very close to what I'm trying to do! The downside is that you need a bit more code, and your props struct tend to be a bit heavier because some big components sometime need to copy a pretty big part of the AppState. |
I don't see a problem with that. Maybe because I do this in my app all the time -- I almost never use objects from the ReSwift-powered If the basic mechanism is indeed to wrap this: store.subscribe(self) {
$0.skipRepeats({ [weak self] (oldState: AppState, newState: AppState) -> Bool in
SomeComponent.Props(items: newState.feedState.items,
datasource: newState.feedState.feeds[id] ?? [])
})
} then I find the result a bit too verbose for my taste, with all the parens and brackets and nested closures: storeConnector = StoreConnector<Props>(mapStateToProps: { (state) -> Props? in
return Props(items: state.feedState.items,
datasource: state.feedState.feeds[id] ?? [])
}, render: { [weak self](props) in
self?.props = props
}) Conceptually, there the A half-assed attempt to simplify could be to just split things up and un-nest them :) storeConnector = StoreConnector<Props>()
.mapStateToProps: { (state) -> Props? in
return Props(items: state.feedState.items,
datasource: state.feedState.feeds[id] ?? [])
}.render { { [weak self] (props) in
self?.props = props
} Then again, maybe I'm being horrible here and don't see how Rx influenced my taste for the worse. |
Again, it's mostly sugar, I like your approach, it was at some point my V0. I'm converting most of my app to this new pattern, and having internal props clearly mapped/calculated and isolated from the store/state is really a big plus in term of code readability, testing and actual render pass. Actual base class could look like this class ConnectedViewController<Props: Equatable>: UIViewController {
private var connector: StoreConnector<Props>!
private(set) var props: Props? {
didSet {
guard let props = props else {
return
}
render(oldProps: oldValue, props: props)
}
}
override func viewDidLoad() {
super.viewDidLoad()
connector = StoreConnector<Props>(mapStateToProps: { [weak self] (state) -> Props? in
return self?.mapStateToProps(state: state)
}, render: { [weak self](props) in
self?.props = props
})
}
deinit {
connector.unsubscribe()
}
func mapStateToProps(state: AppState) -> Props {
fatalError("Need to be implemented by subclass")
}
func render(oldProps: Props?, props: Props) {
fatalError("Need to be implemented by subclass")
}
} |
Browsing issues and found this interesting one. As an iOS developer who worked on React Native with Redux few years ago, found the differences of concepts just like In my understanding, essentially, The I am not sure introducing this concept into ReSwift is a great idea but obviously these two libraries in slightly different ways. |
So finally decided to play around an implementation of something approaching @connect decorator from React/Redux. Was initially made for ReKotlin by our Android team, but works the same with ReSwift.
It's mostly syntax sugar, but our end goal is to make the getter on store.state unavailable, so no more free access to the global store, it should all be in your component local Props struct.
The StoreConnector implementation
And now some example usage
What do you guys think?
The text was updated successfully, but these errors were encountered: