Skip to content

Instantly share code, notes, and snippets.

@AlexanderBollbach
Created September 19, 2019 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexanderBollbach/ae7846a187f78a62c35901c07461aef7 to your computer and use it in GitHub Desktop.
Save AlexanderBollbach/ae7846a187f78a62c35901c07461aef7 to your computer and use it in GitHub Desktop.
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