Skip to content

Instantly share code, notes, and snippets.

@kittinunf
Last active March 31, 2016 04:59
Show Gist options
  • Save kittinunf/c3c8767c685c5b3591a9902ae48259b3 to your computer and use it in GitHub Desktop.
Save kittinunf/c3c8767c685c5b3591a9902ae48259b3 to your computer and use it in GitHub Desktop.
import UIKit
/*:
## Redux
A Predictable state container for not just JavaScript apps
*/
/*:
### Action
Payload of information from app to your __Store__
*/
protocol ActionType {
init()
}
struct DefaultAction : ActionType {
init() { }
}
protocol StandardAction : ActionType {
var type: String { get }
var payload: Any? { get }
}
/*:
### State
Single source of truth for your __Store__
*/
struct TodoState {
var todos: [String]
}
/*:
### Reducer
Function that explains how you react to your __State__ when __Action__ happened
`(previousState, action) -> newState`
*/
func reducer(state: TodoState? = nil, action: ActionType) -> TodoState {
//do something with state
return TodoState(todos: [])
}
/*:
### Store
Object that glues everything together, responsibilities;
* Hold app state
* Allow access state via `getState()`
* Allow action to be dispatched via `dispatch(action)`
* Register/Notify listeners via `subscribe(listener)`
*/
typealias Dispatch = ActionType -> ActionType
protocol DisposableType {
var dispose: () -> () { get }
}
struct DefaultDisposable : DisposableType {
let dispose: () -> ()
init(dispose: () -> ()) {
self.dispose = dispose
}
}
protocol StoreType {
associatedtype State
var getState: () -> State { get }
var dispatch: Dispatch { get }
var subscribe: (State -> ()) -> DisposableType { get }
}
struct Store<State> : StoreType {
let getState: () -> State
let dispatch: Dispatch
let subscribe: (State -> ()) -> DisposableType
init(getState: () -> State, dispatch: Dispatch, subscribe: (State -> ()) -> DisposableType) {
self.getState = getState
self.dispatch = dispatch
self.subscribe = subscribe
}
}
func createStore<State>(reducer: (State?, ActionType) -> State, state: State?) -> Store<State> {
typealias Subscriber = State -> ()
var currentState = state ?? reducer(state, DefaultAction())
var subscribers = [String: Subscriber]()
func _dispatch(action: ActionType) -> ActionType {
//reduce state
currentState = reducer(currentState, action)
//notify subscriber
for (_, s) in subscribers {
s(currentState)
}
return action
}
func _subscribe(subscriber: State -> ()) -> DisposableType {
let key = NSUUID().UUIDString
subscribers[key] = subscriber
return DefaultDisposable(dispose: { subscribers.removeValueForKey(key) })
}
return Store(getState: { currentState }, dispatch: _dispatch, subscribe: _subscribe)
}
/*:
### Let's have some fun with Redux
Assume that we are building todo app
*/
// define actions
struct AddTodoAction : StandardAction {
let type: String = "ADD_TODO"
let payload: Any?
init() {
payload = ""
}
init(payload: String) {
self.payload = payload
}
}
struct RemoveTodoAction : StandardAction {
let type: String = "REMOVE_TODO"
let payload: Any?
init() {
payload = ""
}
init(payload: Int) {
self.payload = payload
}
}
struct ClearTodoAction : StandardAction {
let type: String = "CLEAR_TODO"
let payload: Any?
init() {
payload = nil
}
}
// define reducer
func todoReducer(state: TodoState? = nil, action: ActionType) -> TodoState {
let currentState = state ?? TodoState(todos: [])
var todos = currentState.todos
switch action {
case let action as AddTodoAction:
todos.append(action.payload as! String)
case let action as RemoveTodoAction:
todos.removeAtIndex(action.payload as! Int)
case _ as ClearTodoAction:
todos.removeAll()
default:
break
}
return TodoState(todos: todos)
}
let store = createStore(todoReducer, state: nil)
var count = 0
let d = store.subscribe { s in
print(s.todos)
count += 1
}
store.dispatch(AddTodoAction(payload: "Learn Redux for iOS"))
store.dispatch(AddTodoAction(payload: "Buy shampoo at Tops"))
store.dispatch(AddTodoAction(payload: "Watch series on Netflix"))
store.dispatch(AddTodoAction(payload: "Call daddy"))
store.dispatch(RemoveTodoAction(payload: 2))
store.dispatch(RemoveTodoAction(payload: 0))
store.dispatch(ClearTodoAction())
count
store.getState().todos
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment