Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ReRxSwift or: how I learned to stop worrying and love the state

d4Rk
February 25, 2019

ReRxSwift or: how I learned to stop worrying and love the state

d4Rk

February 25, 2019
Tweet

More Decks by d4Rk

Other Decks in Programming

Transcript

  1. MVC

  2. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller
  3. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller
  4. tab bar controller view controller change data navigation controller view

    controller view controller navigation controller view controller view controller
  5. tab bar controller view controller change data navigation controller view

    controller view controller navigation controller view controller view controller
  6. tab bar controller view controller change data navigation controller view

    controller view controller navigation controller view controller view controller change data
  7. tab bar controller view controller change data navigation controller view

    controller view controller navigation controller view controller view controller change data
  8. action store w/ state reducers view* some data fancy UI

    stuff *view = view + view controller
  9. action store w/ state reducers view* some data fancy UI

    stuff *view = view + view controller subscribe
  10. action store w/ state reducers view* some data fancy UI

    stuff *view = view + view controller subscribe dispatch
  11. action store w/ state reducers view* some data fancy UI

    stuff *view = view + view controller subscribe dispatch
  12. action store w/ state reducers view* some data business logic

    fancy UI stuff *view = view + view controller subscribe dispatch change
  13. // define the store let store = Store<State>(reducer: reducer, state:

    nil) // define a state (important: value type) struct State: StateType { var data: String = "someData" }
  14. // define an action struct ChangeData: Action { let changedData:

    String } // create and dispatch an action let action = ChangeData(changedData: "changedData") store.dispatch(action)
  15. // reducer: action + state = new state func reducer(action:

    Action, state: State?) -> State { } *switch is non-exhausting for simplicity
  16. // reducer: action + state = new state func reducer(action:

    Action, state: State?) -> State { } *switch is non-exhausting for simplicity // create a new state if state is nil var state = state ?? State()
  17. // reducer: action + state = new state func reducer(action:

    Action, state: State?) -> State { } *switch is non-exhausting for simplicity // create a new state if state is nil var state = state ?? State() // switch through desired actions switch action { case let action as ChangeData: }
  18. // reducer: action + state = new state func reducer(action:

    Action, state: State?) -> State { } *switch is non-exhausting for simplicity // create a new state if state is nil var state = state ?? State() // switch through desired actions switch action { case let action as ChangeData: } // perform state change state.data = action.changedData
  19. // reducer: action + state = new state func reducer(action:

    Action, state: State?) -> State { } *switch is non-exhausting for simplicity // create a new state if state is nil var state = state ?? State() // switch through desired actions switch action { case let action as ChangeData: } // perform state change state.data = action.changedData // return the new state return state
  20. class ReSwiftViewController: UIViewController, StoreSubscriber { @IBOutlet weak var button: UIButton!

    @IBOutlet weak var label: UILabel! } // subscribe to store, e.g. in `viewWillAppear` func setup() { store.subscribe(self) }
  21. class ReSwiftViewController: UIViewController, StoreSubscriber { @IBOutlet weak var button: UIButton!

    @IBOutlet weak var label: UILabel! } // subscribe to store, e.g. in `viewWillAppear` func setup() { store.subscribe(self) } // receive state updates from store func newState(state: State) { self.label.text = state.data }
  22. class ReSwiftViewController: UIViewController, StoreSubscriber { @IBOutlet weak var button: UIButton!

    @IBOutlet weak var label: UILabel! } // subscribe to store, e.g. in `viewWillAppear` func setup() { store.subscribe(self) } // receive state updates from store func newState(state: State) { self.label.text = state.data } // dispatch an action to store @IBAction func buttonTap(_ sender: Any) { let action = ChangeData(changedData: "changedData") store.dispatch(action) }
  23. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller store w/ state
  24. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller store w/ state
  25. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller store w/ state change data
  26. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller store w/ state change data
  27. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller store w/ state change data change data
  28. tab bar controller view controller navigation controller view controller view

    controller navigation controller view controller view controller store w/ state change data change data
  29. // define data as a subject ("stream") let data =

    PublishSubject<String>() *disposing is left out for simplicity
  30. // define data as a subject ("stream") let data =

    PublishSubject<String>() // subscribe to data subject* data.asObservable() .subscribe(onNext: { element in label.rx.text = element }) *disposing is left out for simplicity
  31. // define data as a subject ("stream") let data =

    PublishSubject<String>() // subscribe to data subject* data.asObservable() .subscribe(onNext: { element in label.rx.text = element }) // or just bind data subject to label* data.bind(to: label.rx.text) *disposing is left out for simplicity
  32. // define data as a subject ("stream") let data =

    PublishSubject<String>() // subscribe to data subject* data.asObservable() .subscribe(onNext: { element in label.rx.text = element }) // or just bind data subject to label* data.bind(to: label.rx.text) *disposing is left out for simplicity // trigger an update data.onNext("changedData")
  33. // define props extension ReRxSwiftViewController: Connectable { } struct Props

    { let data: String } // state to props mapping private let mapStateToProps = { (state: State) in }
  34. // define props extension ReRxSwiftViewController: Connectable { } struct Props

    { let data: String } // state to props mapping private let mapStateToProps = { (state: State) in } return ReRxSwiftViewController.Props( data: state.data )
  35. // define actions extension ReRxSwiftViewController: Connectable { } struct Actions

    { let changeData: (String) -> Void } // dispatch to actions mapping private let mapDispatchToActions = { (dispatch: @escaping DispatchFunction) in }
  36. // define actions extension ReRxSwiftViewController: Connectable { } struct Actions

    { let changeData: (String) -> Void } // dispatch to actions mapping private let mapDispatchToActions = { (dispatch: @escaping DispatchFunction) in } return ReRxSwiftViewController.Actions( changeData: { dispatch(ChangeData(changedData: $0)) } )
  37. class ReRxSwiftViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet

    weak var label: UILabel! } // set up connection with store and mappings let connection = Connection(store: store, mapStateToProps: mapStateToProps, mapDispatchToActions: mapDispatchToActions)
  38. class ReRxSwiftViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet

    weak var label: UILabel! } // set up connection with store and mappings let connection = Connection(store: store, mapStateToProps: mapStateToProps, mapDispatchToActions: mapDispatchToActions) // establish connection and bind to a label func setup() { self.connection.connect() self.connection.bind(\Props.data, to: self.label.rx.text) }
  39. class ReRxSwiftViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet

    weak var label: UILabel! } // set up connection with store and mappings let connection = Connection(store: store, mapStateToProps: mapStateToProps, mapDispatchToActions: mapDispatchToActions) // establish connection and bind to a label func setup() { self.connection.connect() self.connection.bind(\Props.data, to: self.label.rx.text) } // dispatch an action
 @IBAction func buttonTap(_ sender: Any) { self.connection.actions.changeData("changedData") }
  40. ReSwift github.com/ReSwift/ReSwift Thinking in Redux
 hackernoon.com/thinking-in-redux-when-all-youve-known-is-mvc-c78a74d35133 Unidirectional Data Flow: Shrinking

    Massive View Controllers
 academy.realm.io/posts/benji-encz-unidirectional-data-flow-swift MVVM is lipstick on a pig
 sharpfivesoftware.com/2016/07/20/mvvm-is-lipstick-on-a-pig Architecture Wars: A New Hope
 swifting.io/blog/2016/09/07/architecture-wars-a-new-hope Model View Whatever
 khanlou.com/2014/03/model-view-whatever
  41. The introduction to Reactive Programming you've been missing
 gist.github.com/staltz/868e7e9bc2a7b8c1f754 Interactive

    diagrams of Rx Observables
 rxmarbles.com RxSwift github.com/ReactiveX/RxSwift