Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Hello, ReactorKit ๐
Search
Suyeol Jeon
June 28, 2018
Programming
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Hello, ReactorKitย ๐
https://www.slideshare.net/devxoul/hello-reactorkit
Suyeol Jeon
June 28, 2018
More Decks by Suyeol Jeon
See All by Suyeol Jeon
แแ ฅแผแแ กแผแแ กแแ ณแซ iOS แแ ขแแ กแฏแแ ก แแ ฌแแ ต
devxoul
2
260
แ แ ฆแแ ฅแแ ต แแ ณแ แ ฉแแ ฆแจแแ ณแแ ฆแแ ฅ แแ ดแแ ฉแซแแ ฅแผ แแ ฎแแ ตแธแแ กแแ ต
devxoul
1
2.6k
Let's TDD
devxoul
0
110
Build Funnels with Google BigQuery
devxoul
0
60
RxSwift แแ ตแแ กแจแแ กแแ ต
devxoul
1
370
ReactorKit์ผ๋ก ๋จ๋ฐฉํฅ ๋ฐ์ํ ์ฑ ๋ง๋ค๊ธฐ
devxoul
0
180
Swift - ํผ์ ๊ณต๋ถํ๋ฉด ๋ถ๋ช ํ ์ํ ํ ๋๊น ๊ฐ์ด ๊ณต๋ถํ๊ธฐ
devxoul
10
3.3k
แแ ฉแแแ ณแซ แแ ตแแ กแแ ตแแ ฅ, แแ กแแ ณแซ แแ ณแ แ ฉแแ ฆแจแแ ณแแ ขแแ ตแแ ฅ, แแ ตแแ กแผแแ กแซ แแ ขแแ กแฏแแ ก
devxoul
0
130
Other Decks in Programming
See All in Programming
ใกใฝใใใฎใธใงใใชใฏในใงGoใฎๅคขใฏๅบใใใ๏ผ / Kyoto.go #65
utgwkk
3
770
New "Type" system on PicoRuby
pocke
1
930
OSใใฉใOS
arkw
0
570
ไฝใฃใฆๅญฆใถใ JSX (TSX) ใฉใณใฟใคใ ใฎๅบๆฌ
syumai
7
1.6k
ใใฎใในใใ่ชฌๆใงใใพใใ๏ผ~LWใในใๆฆ็ฅFW~ใฎใ็ดนไป
nakahara
0
130
ไพๅญ้ขไฟใใไพๅญ็ฉใธโDependencyใจใใ่จ่ใฎๆญดๅฒใใฒใ่งฃใ
j_lee
0
120
ๆ่ก่จไบใ ๅฐ้ๅฎถใจใใฆใฎใใญใฐใฉใใ ่จ่ชๅ
mizchi
13
6k
ไปฃๆฐ็ใใผใฟๅใฃใฆไฝใๅฌใใใฎ๏ผ #frontend_phpcon_do
kajitack
8
3.7k
็ๆAIๆไปฃใซใใๅนใGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
Observability in Practice๏ผGrafana ่ Edge Device SRE ็้ฃไบไบ
blueswen
0
160
JavaใฎๅใจAIๆไปฃใซๅใๅคงไบใช็็ฑ / java types and type in AI era
kishida
2
140
Contextใจใฏใชใซใ
chiroruxx
1
320
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Faster Mobile Websites
deanohume
310
31k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.4k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
840
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
140
Embracing the Ebb and Flow
colly
88
5.1k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
Music & Morning Musume
bryan
47
7.2k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
210
Measuring & Analyzing Core Web Vitals
bluesmoon
9
870
WCS-LA-2024
lcolladotor
0
630
Transcript
Hello, ReactorKit! Suyeol Jeon https://github.com/devxoul
Jeon Suyeol StyleShare Inc. Open Source Lover Then URLNavigator RxSwift
ObjectMapper
Why?
Why? Massive View Controller
Why? Massive View Controller RxSwift State Managing
Massive View Controller https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Massive View Controller https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Massive View Controller https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
RxSwift State Managing Cyclic Data Dependencies
RxSwift State Managing currentValue increaseValue()
RxSwift State Managing currentValue increaseValue() last state
RxSwift State Managing currentValue increaseValue() last state result
RxSwift State Managing Cyclic Data Dependencies
RxSwift State Managing Cyclic Data Dependencies Pagination List operation Value
update ...
RxSwift State Managing After a while...
RxSwift State Managing After a while... Variable<Int> PublishSubject<Int> PublishRelay<[Item]> Variable<User>
BehaviorSubject<String> Variable<String>
I wanted to... 1. Avoid Massive View Controller
I wanted to... 1. Avoid Massive View Controller 2. Take
advantages of RxSwift
I wanted to... 1. Avoid Massive View Controller 2. Take
advantages of RxSwift 3. Manage states gracefully
ReactorKit
ReactorKit can... 1. Avoid Massive View Controller โ
ReactorKit can... 1. Avoid Massive View Controller โ Separates responsibilities
of view and logic
ReactorKit can... 1. Avoid Massive View Controller โ Separates responsibilities
of view and logic View Controller becomes simple
ReactorKit can... 2. Take advantages of RxSwift โ
ReactorKit can... 2. Take advantages of RxSwift โ Based on
RxSwift
ReactorKit can... 2. Take advantages of RxSwift โ Based on
RxSwift All of RxSwift features are available
ReactorKit can... 3. Manage states gracefully โ
ReactorKit can... 3. Manage states gracefully โ Unidirectional data flow
ReactorKit can... 3. Manage states gracefully โ Unidirectional data flow
Modify states only in reduce()
ReactorKit can... 3. Manage states gracefully โ Unidirectional data flow
Modify states only in reduce() State management became easy
ReactorKit can... Be the future ~1.1K โญ ~50K downloads ~900
apps https://starcharts.herokuapp.com/ReactorKit/ReactorKit
ReactorKit can... Be the future ~1.1K โญ ~50K downloads ~900
apps https://starcharts.herokuapp.com/ReactorKit/ReactorKit
Basic Concept
Basic Concept Abstraction of User Interaction Abstraction of View State
Basic Concept Renders view states Handles user interactions ViewController, Cell,
...
Basic Concept protocol View { associatedtype Reactor var disposeBag: DisposeBag
// gets called when // self.reactor is changed func bind(reactor: Reactor) }
Basic Concept protocol StoryboardView { associatedtype Reactor var disposeBag: DisposeBag
// gets called when // the view is loaded func bind(reactor: Reactor) } // for Storyboard support
Basic Concept Performs business logic Manages states Corresponds to view
Basic Concept protocol Reactor { associatedtype Action associatedtype Mutation associatedtype
State var initialState: State }
Basic Concept Based on RxSwift
Data Flow
Data Flow
Data Flow Action โ State โ
Data Flow Action โ Mutation โ State
Data Flow Action โ Mutation โ State State manipulator
Data Flow State manipulator Async-able Action โ Mutation โ State
Data Flow State manipulator Async-able Not exposed to view Action
โ Mutation โ State
Data Flow (Action) -> Observable<Mutation> (State, Mutation) -> State
Data Flow
Data Flow class ProfileViewReactor: Reactor { enum Action { }
struct State { } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { var isFollowing: Bool // view state } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { var isFollowing: Bool // view state } } Execute user follow API โ Change state
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { var isFollowing: Bool // view state } } Execute user follow API โ Change state Async
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } enum Mutation { } struct State { var isFollowing: Bool // view state } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } enum Mutation { case setFollowing(Bool) // change state } struct State { var isFollowing: Bool // view state } }
Data Flow
Data Flow Tap follow button
Data Flow Action.follow
Data Flow Action.follow
Data Flow UserService.follow()
Data Flow UserService
Data Flow Observable<Bool>
Data Flow
Data Flow Mutation.setFollowing(true)
Data Flow Mutation.setFollowing(true)
Data Flow isFollowing = true
Data Flow Update follow button
Data Flow
More Examples
More Examples
Advanced View Communications Testing View and Reactor
View Communications ProfileViewController ProfileViewReactor
View Communications UICollectionView ProfileViewController ProfileViewReactor
View Communications UICollectionView ProfileViewController ProfileViewReactor UserCell
View Communications Passing user data Observing button tap
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. User
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. User 2. User
View Communications - Passing user data // ProfileViewReactor struct State
{ }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? } // ProfileViewController let cell = collectionView.dequeue... return cell
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? } // ProfileViewController let cell = collectionView.dequeue... if let reactor = self.reactor { } return cell
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? } // ProfileViewController let cell = collectionView.dequeue... if let reactor = self.reactor { cell.user = reactor.currentState.user } return cell
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor 1. rx.tap
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor 2. Action.follow 1. rx.tap
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor 2. Action.follow 1. rx.tap Reactive Extension
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { } }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { return self.base.followButton.rx.tap } }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var tap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap .map { Reactor.Action.follow }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var tap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap .map { Reactor.Action.follow } .bind(to: reactor.action)
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var tap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap .map { Reactor.Action.follow } .bind(to: reactor.action) .disposed(by: self.disposeBag)
View Communications UICollectionView ProfileViewController ProfileViewReactor UserCell
View Communications UICollectionView ProfileViewController ProfileViewReactor UserCell UserCellReactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor UserCell Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. CellReactor UserCell Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. CellReactor 2. CellReactor UserCell Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. CellReactor 2. CellReactor UserCell Reactor
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? var userCellReactor: UserCellReactor? }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? var userCellReactor: UserCellReactor? } // ProfileViewController cell.user = reactor.currentState.user
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? var userCellReactor: UserCellReactor? } // ProfileViewController cell.user = reactor.currentState.user cell.reactor = reactor.currentState.userCellReactor
Testing View and Reactor What to test? View Reactor
Testing View and Reactor What to test? View Action: on
user interaction โ action sent? Reactor
Testing View and Reactor What to test? View Action: on
user interaction โ action sent? State: on state change โ view updated? Reactor
Testing View and Reactor What to test? View Action: on
user interaction โ action sent? State: on state change โ view updated? Reactor State: on action receive โ state updated?
Testing View and Reactor How to test?
Testing View and Reactor How to test? Reactor.stub()
Testing View and Reactor How to test? Reactor.stub() state: set
fake state
Testing View and Reactor How to test? Reactor.stub() state: set
fake state action: send fake action
Testing View and Reactor How to test? Reactor.stub() state: set
fake state action: send fake action actions: log received actions
Testing View and Reactor - View Action
Testing View and Reactor - View Action When: follow button
taps Then: sends follow action
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when let button = viewController.userCell.followButton // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when let button = viewController.userCell.followButton button.sendActions(for: .touchUpInside) // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when let button = viewController.userCell.followButton button.sendActions(for: .touchUpInside) // then let lastAction = reactor.stub.actions.last XCTAssertEqual(lastAction, .follow)
Testing View and Reactor - View State When: following the
user Then: button is selected
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() // when // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true // when // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true let cell = UserCell() cell.reactor = cellReactor // when // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true let cell = UserCell() cell.reactor = cellReactor // when cellReactor.stub.state.value.isFollowing = true // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true let cell = UserCell() cell.reactor = cellReactor // when cellReactor.stub.state.value.isFollowing = true // then XCTAssertTrue(cell.followButton.isSelected)
Testing View and Reactor - Reactor State When: receive follow
action Then: update following state ProfileView Reactor
Testing View and Reactor - Reactor State // given let
reactor = ProfileViewReactor() // when // then
Testing View and Reactor - Reactor State // given let
reactor = ProfileViewReactor() // when reactor.action.onNext(.follow) // then
Testing View and Reactor - Reactor State // given let
reactor = ProfileViewReactor() // when reactor.action.onNext(.follow) // then let user = reactor.currentState.user XCTAssertEqual(user?.isFollowing, true)
Future Ideas Development Documentation Community
Development Testing Support SectionReactor AlertReactor ModelReactor Plugins ... Nested stub
Dummy reactor ... Building Extensions
Documentation Best Practices Translations Code-level Documentation
Community RxSwift Slack #reactorkit (English) https://rxswift-slack.herokuapp.com Swift Korea Slack #reactorkit
(Korean) http://slack.swiftkorea.org
https://reactorkit.io