Created
September 19, 2019 13:29
-
-
Save AlexanderBollbach/ae7846a187f78a62c35901c07461aef7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
@UIApplicationMain | |
class AppDelegate: UIResponder, UIApplicationDelegate { | |
var window: UIWindow? | |
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { | |
test() | |
return true | |
} | |
} | |
// | |
struct Bar { | |
let id: Int | |
var name: String | |
} | |
extension Bar: HasId { } | |
extension Foo: HasId { } | |
struct Foo { | |
let id: Int | |
var bars: [Bar] | |
} | |
struct AppState { | |
var foos: [Foo] = [] | |
} | |
enum BarAction { | |
case changeName(String) | |
} | |
enum FooAction { | |
case bar(action: ArrayAction<BarAction>) | |
} | |
enum AppAction { | |
case foo(action: ArrayAction<FooAction>) | |
} | |
struct AppAction { | |
static func changeBarName(to: String, fooId: Int, barId: Int) -> AppAction { | |
return AppAction.foo( | |
action: .mutateOne( | |
id: fooId, | |
action: FooAction.bar( | |
action: .mutateOne( | |
id: barId, | |
action: BarAction.changeName(to) | |
) | |
) | |
) | |
) | |
} | |
} | |
func barReducer(state: inout Bar, action: BarAction) { | |
switch action { | |
case let .changeName(newName): | |
state.name = newName | |
} | |
} | |
func fooReducer(state: inout Foo, action: FooAction) { | |
switch action { | |
case let .bar(action): | |
makeArrayReducer(elementReducer: barReducer)(&state.bars, action) | |
} | |
} | |
func appReducer(state: inout AppState, action: AppAction) { | |
switch action { | |
case let .foo(action): | |
makeArrayReducer(elementReducer: fooReducer)(&state.foos, action) | |
} | |
} | |
protocol HasId { | |
var id: Int { get } | |
} | |
enum ArrayAction<SubAction> { | |
case deleteOne(id: Int) | |
case mutateOne(id: Int, action: SubAction) | |
} | |
func makeArrayReducer<T: HasId, SubAction>( | |
elementReducer: @escaping (inout T, SubAction) -> Void | |
) -> (inout [T], ArrayAction<SubAction>) -> Void { | |
return { state, action in | |
switch action { | |
case let .deleteOne(id): | |
if let id = state.firstIndex(where: { $0.id == id }) { | |
state.remove(at: id) | |
} | |
case let .mutateOne(id, action): | |
if let id = state.firstIndex(where: { $0.id == id }) { | |
elementReducer(&state[id], action) | |
} | |
} | |
} | |
} | |
func test() { | |
var state = AppState( | |
foos: [ | |
Foo( | |
id: 1, | |
bars: [] | |
), | |
Foo( | |
id: 2, | |
bars: [ | |
Bar( | |
id: 1, | |
name: "old name" | |
) | |
] | |
) | |
] | |
) | |
print(state) | |
assert(state.foos.count == 2) | |
appReducer( | |
state: &state, | |
action: .foo( | |
action: ArrayAction.deleteOne(id: 1) | |
) | |
) | |
print(state) | |
assert(state.foos.count == 1) | |
appReducer( | |
state: &state, | |
action: Actions.changeBarName(to: "new value", fooId: 2, barId: 1) | |
) | |
print(state) | |
assert(state.foos[0].bars[0].name == "new value") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment