Skip to content
This repository was archived by the owner on May 13, 2020. It is now read-only.

Commit 1c250e2

Browse files
committed
Segragate a substate mutation in a dedicated reducer
1 parent 78fb8f8 commit 1c250e2

File tree

8 files changed

+158
-99
lines changed

8 files changed

+158
-99
lines changed

RxReduce.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
1A26CF05212BA111008A6D7B /* Lens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A26CF04212BA111008A6D7B /* Lens.swift */; };
11+
1A26CF07212BA15D008A6D7B /* Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A26CF06212BA15D008A6D7B /* Reducer.swift */; };
1012
1A2A7571208D4750009883BF /* RxReduce.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A2A7567208D474F009883BF /* RxReduce.framework */; };
1113
1A2A7576208D4750009883BF /* ActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A7575208D4750009883BF /* ActionTests.swift */; };
1214
1A2A7578208D4750009883BF /* RxReduce.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A2A756A208D4750009883BF /* RxReduce.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -49,6 +51,8 @@
4951
/* End PBXCopyFilesBuildPhase section */
5052

5153
/* Begin PBXFileReference section */
54+
1A26CF04212BA111008A6D7B /* Lens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lens.swift; sourceTree = "<group>"; };
55+
1A26CF06212BA15D008A6D7B /* Reducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reducer.swift; sourceTree = "<group>"; };
5256
1A2A7567208D474F009883BF /* RxReduce.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxReduce.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5357
1A2A756A208D4750009883BF /* RxReduce.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RxReduce.h; sourceTree = "<group>"; };
5458
1A2A756B208D4750009883BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -112,6 +116,8 @@
112116
children = (
113117
1A2A756A208D4750009883BF /* RxReduce.h */,
114118
1A2A7588208D51E2009883BF /* Action.swift */,
119+
1A26CF04212BA111008A6D7B /* Lens.swift */,
120+
1A26CF06212BA15D008A6D7B /* Reducer.swift */,
115121
1A2A7589208D51E2009883BF /* Store.swift */,
116122
1A2A756B208D4750009883BF /* Info.plist */,
117123
);
@@ -278,6 +284,8 @@
278284
files = (
279285
1A2A758C208D51E2009883BF /* Store.swift in Sources */,
280286
1A2A758B208D51E2009883BF /* Action.swift in Sources */,
287+
1A26CF07212BA15D008A6D7B /* Reducer.swift in Sources */,
288+
1A26CF05212BA111008A6D7B /* Lens.swift in Sources */,
281289
);
282290
runOnlyForDeploymentPostprocessing = 0;
283291
};

RxReduce/Lens.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// Lens.swift
3+
// RxReduce
4+
//
5+
// Created by Thibault Wittemberg on 2018-08-20.
6+
// Copyright © 2018 WarpFactor. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct Lens<State, SubState> {
12+
let get: (State) -> SubState
13+
let set: (State, SubState) -> State
14+
}

RxReduce/Reducer.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// Reducer.swift
3+
// RxReduce
4+
//
5+
// Created by Thibault Wittemberg on 2018-08-20.
6+
// Copyright © 2018 WarpFactor. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct Reducer<State: Equatable, SubState: Equatable> {
12+
let lens: Lens<State, SubState>
13+
let reducer: (State, Action) -> SubState
14+
15+
func apply(state: State, action: Action) -> State {
16+
return self.lens.set(state, self.reducer(state, action))
17+
}
18+
}

RxReduce/Store.swift

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,49 +10,53 @@ import Foundation
1010
import RxSwift
1111
import RxCocoa
1212

13-
/// A Reducer mutates an input state into an output state according to an action
14-
public typealias Reducer<StateType: Equatable> = (_ state: StateType, _ action: Action) -> StateType
15-
16-
/// A Middleware has not effect on the state, it us just triggered by a dispatch action
17-
public typealias Middleware<StateType: Equatable> = (_ state: StateType, _ action: Action) -> Void
13+
///// A Reducer mutates an input state into an output state according to an action
14+
//public typealias Reducer<StateType: Equatable> = (_ state: StateType, _ action: Action) -> StateType
15+
//
16+
///// A Middleware has not effect on the state, it us just triggered by a dispatch action
17+
//public typealias Middleware<StateType: Equatable> = (_ state: StateType, _ action: Action) -> Void
1818

1919
/// A Store holds the state, mutate the state through actions / reducers and exposes the state via a Driver
2020
/// A Store is dedicated to a State Type
21-
public final class Store<StateType: Equatable> {
21+
public final class Store<State: Equatable> {
2222

23-
private var state: StateType
24-
private let reducers: ContiguousArray<Reducer<StateType>>
25-
private let middlewares: ContiguousArray<Middleware<StateType>>?
23+
public typealias ReducerFunction = (State, Action) -> State
2624

27-
public init(withState state: StateType,
28-
withReducers reducers: ContiguousArray<Reducer<StateType>>,
29-
withMiddlewares middlewares: ContiguousArray<Middleware<StateType>>? = nil) {
25+
private var state: State
26+
private var reducers = [ReducerFunction]()
27+
// private let reducers: ContiguousArray<Reducer<StateType>>
28+
// private let middlewares: ContiguousArray<Middleware<StateType>>?
29+
30+
public init(withState state: State) {
3031
self.state = state
31-
self.reducers = reducers
32-
self.middlewares = middlewares
32+
// self.middlewares = middlewares
33+
}
34+
35+
public func register<SubState: Equatable> (reducer: Reducer<State, SubState>) {
36+
self.reducers.append(reducer.apply)
3337
}
3438

35-
public func dispatch(action: Action) -> Observable<StateType> {
39+
public func dispatch(action: Action) -> Observable<State> {
3640
// every received action is converted to an async action
3741
return action
3842
.toAsync()
39-
.do(onNext: { [unowned self] (action) in
40-
self.middlewares?.forEach({ [unowned self] (middleware) in
41-
middleware(self.state, action)
42-
})
43-
})
44-
.map { (action) -> StateType in
45-
46-
return self.reducers.reduce(self.state, { (previousState, reducer) -> StateType in
47-
return reducer(previousState, action)
43+
// .do(onNext: { [unowned self] (action) in
44+
// self.middlewares?.forEach({ [unowned self] (middleware) in
45+
// middleware(self.state, action)
46+
// })
47+
// })
48+
.map { (action) -> State in
49+
50+
return self.reducers.reduce(self.state, { (currentState, reducer) -> State in
51+
return reducer(currentState, action)
4852
})
4953
}.do(onNext: { [unowned self] (newState) in
5054
self.state = newState
5155
}).distinctUntilChanged()
5256
}
5357

54-
public func dispatch<SubStateType: Equatable>(action: Action, on: @escaping (StateType) -> SubStateType) -> Observable<SubStateType> {
55-
return self.dispatch(action: action).map { on($0) }
56-
}
58+
// public func dispatch<SubStateType: Equatable>(action: Action, on: @escaping (State) -> SubStateType) -> Observable<SubStateType> {
59+
// return self.dispatch(action: action).map { on($0) }
60+
// }
5761

5862
}

RxReduceTests/State/Actions.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@ struct DecreaseAction: Action {
1717
let decrement: Int
1818
}
1919

20-
struct ClearCounterAction: Action {
20+
struct ClearAction: Action {
2121
}
2222

23-
struct AddUserAction: Action {
23+
struct LogUserAction: Action {
2424
let user: String
2525
}
26-
27-
struct ClearUsersAction: Action {
28-
}

RxReduceTests/State/Reducers.swift

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
import Foundation
1010
import RxReduce
1111

12-
func counterReducer (state: TestState, action: Action) -> TestState {
12+
func counterReduce (state: TestState, action: Action) -> CounterState {
1313

14-
var currentState = state
1514
var currentCounter = 0
1615

1716
// we extract the current counter value from the current state
18-
switch currentState.counterState {
17+
switch state.counterState {
1918
case .decreasing(let counter), .increasing(let counter):
2019
currentCounter = counter
2120
default:
@@ -25,32 +24,25 @@ func counterReducer (state: TestState, action: Action) -> TestState {
2524
// according to the action we mutate the counter state
2625
switch action {
2726
case let action as IncreaseAction:
28-
currentState.counterState = .increasing(currentCounter+action.increment)
29-
return currentState
27+
return .increasing(currentCounter+action.increment)
3028
case let action as DecreaseAction:
31-
currentState.counterState = .decreasing(currentCounter-action.decrement)
32-
return currentState
33-
case is ClearCounterAction:
34-
currentState.counterState = .empty
35-
return currentState
29+
return .decreasing(currentCounter-action.decrement)
30+
case is ClearAction:
31+
return .empty
3632
default:
37-
return currentState
33+
return state.counterState
3834
}
3935
}
4036

41-
func usersReducer (state: TestState, action: Action) -> TestState {
42-
43-
var currentState = state
37+
func userReduce (state: TestState, action: Action) -> UserState {
4438

4539
// according to the action we mutate the users state
4640
switch action {
47-
case let action as AddUserAction:
48-
currentState.users.append(action.user)
49-
return currentState
50-
case is ClearUsersAction:
51-
currentState.users.removeAll()
52-
return currentState
41+
case let action as LogUserAction:
42+
return .loggedIn(name: action.user)
43+
case is ClearAction:
44+
return .loggedOut
5345
default:
54-
return currentState
46+
return state.userState
5547
}
5648
}

RxReduceTests/State/States.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ import RxReduce
1111

1212
struct TestState: Equatable {
1313
var counterState: CounterState
14-
var users: [String]
14+
var userState: UserState
1515
}
1616

1717
enum CounterState: Equatable {
1818
case empty
1919
case increasing (Int)
2020
case decreasing (Int)
2121
}
22+
23+
enum UserState: Equatable {
24+
case loggedIn (name: String)
25+
case loggedOut
26+
}

0 commit comments

Comments
 (0)