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

VueFlux - Flux inspired state managements

VueFlux - Flux inspired state managements

2018/03/22 iOS Flux/Redux勉強会
Twitter hashtag: #iOSFluxRedux勉強会

VueFlux: https://github.com/ra1028/VueFlux
VueFluxExample-GitHub: https://github.com/ra1028/VueFluxExample-GitHub

Ryo Aoyama

March 22, 2018
Tweet

More Decks by Ryo Aoyama

Other Decks in Programming

Transcript

  1. VueFlux Flux inspired state managements 2018/03/22 iOS Flux / Redux

    ษڧձ #iOSFluxReduxษڧձ Ryo Aoyama - @ra1028
  2. Profile - Ryo Aoyama - CyberAgent, Inc / FRESH! /

    2016/04~ - GitHub: @ra1028 - Twitter: @ra1028fe5
  3. Actions enum UserAction { case searched(result: Result<[User], Session.Error>) } extension

    Actions where State == UserState { func search(query: String) -> Disposable { let request = SearchUser(query: query, page: 1, perPage: 100) return Session.send(request: request).observe { result in self.dispatch(action: .searched(result: result)) } } }
  4. Actions enum UserAction { case searched(result: Result<[User], Session.Error>) } extension

    Actions where State == UserState { func search(query: String) -> Disposable { let request = SearchUser(query: query, page: 1, perPage: 100) return Session.send(request: request).observe { result in self.dispatch(action: .searched(result: result)) } } } ঢ়ଶΛભҠ͢ΔͨΊͷActionΛఆٛ͢Δ ܕ͸GenericsͰܾఆ͞ΕΔͷͰͳΜͰ΋OK
  5. enum UserAction { case searched(result: Result<[User], Session.Error>) } extension Actions

    where State == UserState { func search(query: String) -> Disposable { let request = SearchUser(query: query, page: 1, perPage: 100) return Session.send(request: request).observe { result in self.dispatch(action: .searched(result: result)) } } } Actions APIϦΫΤετͷ݁Ռ౳ʹԠͯ͡ActionΛૹ৴ ݕࡧ݁ՌΛdispatch
  6. struct UserMutations: Mutations { func commit(action: UserAction, state: UserState) {

    switch action { case .searched(result: .success(let users)): state.cellModels.value = users.map(UserCellModel.init) case .searched(result: .failure): state.cellModels.value.removeAll() } } } Mutations
  7. struct UserMutations: Mutations { func commit(action: UserAction, state: UserState) {

    switch action { case .searched(result: .success(let users)): state.cellModels.value = users.map(UserCellModel.init) case .searched(result: .failure): state.cellModels.value.removeAll() } } } Mutations ActionʹPayloadͱͯ͠ఴ෇͞Εͨ஋Λ࢖ͬͯStateΛߋ৽͢Δ
  8. State final class UserState: State { typealias Action = UserAction

    typealias Mutations = UserMutations fileprivate let cellModels = Variable<[UserCellModel]>([]) }
  9. State final class UserState: State { typealias Action = UserAction

    typealias Mutations = UserMutations fileprivate let cellModels = Variable<[UserCellModel]>([]) } State͕ActionͱMutationsΛassociatedtypeʹ࣋ͪɺܕΛଋറ͢Δ
  10. State final class UserState: State { typealias Action = UserAction

    typealias Mutations = UserMutations fileprivate let cellModels = Variable<[UserCellModel]>([]) } MutationsΛಉ͡ϑΝΠϧ಺ʹهड़͠ɺfileprivateʹ͢Δ͜ͱͰ MutationsҎ֎͔ΒͷมߋΛڐՄ͠ͳ͍
  11. Computed extension Computed where State == UserState { var cellModels:

    Constant<[UserCellModel]> { return state.cellModels.constant } var countText: Signal<String> { return state.cellModels.signal.map { String($0.count) } } }
  12. extension Computed where State == UserState { var cellModels: Constant<[UserCellModel]>

    { return state.cellModels.constant } var countText: Signal<String> { return state.cellModels.signal.map { String($0.count) } } } Computed ஋Λ௚઀ߋ৽Ͱ͖ͳ͍Α͏ʹɺimmutableʹม׵͢Δ
  13. extension Computed where State == UserState { var cellModels: Constant<[UserCellModel]>

    { return state.cellModels.constant } var countText: Signal<String> { return state.cellModels.signal.map { String($0.count) } } } Computed View͕࢖͍΍͍͢஋ʹม׵͢Δ
  14. Store private let store = Store<UserState>(state: .init(), mutations: .init(), executor:

    .queue(.global())) store.computed.countText.bind(to: countLabel, \.text) store.computed.cellModels.signal.bind(to: tableView, on: .queue(.main)) { tableView, _ in tableView.reloadData() } store.actions.search(query: "GitHub")
  15. Store private let store = Store<UserState>(state: .init(), mutations: .init(), executor:

    .queue(.global())) store.computed.countText.bind(to: countLabel, \.text) store.computed.cellModels.signal.bind(to: tableView, on: .queue(.main)) { tableView, _ in tableView.reloadData() } store.actions.search(query: "GitHub") ॳظԽ࣌ʹStateͱMutationsΛ౉͢ ͜ͷͱ͖౉͢Executor͕MutationsͰͷঢ়ଶมߋͷContextΛܾఆ͢Δ
  16. Store private let store = Store<UserState>(state: .init(), mutations: .init(), executor:

    .queue(.global())) store.computed.countText.bind(to: countLabel, \.text) store.computed.cellModels.signal.bind(to: tableView, on: .queue(.main)) { tableView, _ in tableView.reloadData() } store.actions.search(query: "GitHub") Computedͷ஋ΛViewʹbind͓ͯ͘͠
  17. Store private let store = Store<UserState>(state: .init(), mutations: .init(), executor:

    .queue(.global())) store.computed.countText.bind(to: countLabel, \.text) store.computed.cellModels.signal.bind(to: tableView, on: .queue(.main)) { tableView, _ in tableView.reloadData() } store.actions.search(query: "GitHub") StoreͷΠϯελϯε͕࣋ͭActionsͷؔ਺Λ࣮ߦ͢Δ͜ͱͰɺ ݸผʹߋ৽Ͱ͖Δ
  18. Store private let store = Store<UserState>(state: .init(), mutations: .init(), executor:

    .queue(.global())) store.computed.countText.bind(to: countLabel, \.text) store.computed.cellModels.signal.bind(to: tableView, on: .queue(.main)) { tableView, _ in tableView.reloadData() } Store<UserState>.actions.search(query: "GitHub") staticͳActions͔Βؔ਺Λ࣮ߦ͢ΔͱΞϓϦͷͲ͔͜ΒͰ΋ Store<UserState>ܕͷશͯͷΠϯελϯεʹActionΛbroadcastͰ͖Δ