Skip to content

ReduxKit/ReduxKit

Repository files navigation

ReduxKit

Build Status Code coverage status Doc coverage Carthage Version Cocoapods Compatible Platform License MIT

Merge / deprecation announcement:

ReduxKit and Swift-Flow have joined forces! The result is ReSwift.

The nitty gritty: We decided to deprecate ReduxKit and keep it as a reference implementation of how an almost exact Redux implementation in Swift can be accomplished.

Swift-Flow has adopted the name ReSwift and moved to it's new home as a nod to it's Redux roots that remain at it's core. Going forward, our combined efforts will be focused on ReSwift and surrounding tooling.

ReduxKit:

  • Will no longer be actively maintained
  • Will remain as a reference implementation of Redux in Swift
  • Pull requests are still welcome

What are you waiting for? Go get started with ReSwift today!

Introduction

ReduxKit is a swift implementation of the JavaScript Redux library by Dan Abramov and the React Community. ReduxKit stays as close as possible to Redux while bringing in Swift ways of doing things where appropriate.

A thorough walk through and description of the framework can be found at the official Redux repository: Redux.

It is currently implemented in a few swift apps and is frequently updated. Additions, middleware and help will be very much appreciated! So if you're trying it out and have any suggestions - feel free to post an issue and I'll be on it.

Contents

API

Quick start

The easiest way to include ReduxKit is via Carthage:

iOS 8.0 required

Add ReduxKit to Cartfile

github "ReduxKit/ReduxKit" ~> 0.1

Run in terminal:

$ carthage update

Add ReduxKit to your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

pod 'ReduxKit', '~> 0.1'

Then, run the following command:

$ pod install

The Gist

A more advanced Swift example of the original gist

import ReduxKit

/**
 This is an extremely simple and flexible action. The only requirement for actions is that they
 conform to the Action protocol.

 The Action protocol can be inherited from for app specific Action requirements. For a good example
 of this, see FluxStandardAction and the implementing types in the source.

 Action can be implemented as an enum, struct or class.
 */
struct IncrementAction: Action {
    let payload: Int
    init(payload: Int = 1) {
        self.payload = payload
    }
}


/**
 * And implemented as an enum action
 */
enum CountEnumAction: Action {
    case Increment
    case Decrement
    case Set(Int)
}



/**
 This is a simple reducer. It is a pure function that follows the syntax (State, Action) -> State.
 It describes how an action transforms the previous state into the next state.

 Instead of using the Action.type property - as is done in the regular Redux framework we use the
 power of Swifts static typing to deduce the action.
 */
func counterReducer(previousState: Int?, action: Action) -> Int {
    // Declare the reducers default value
    let defaultValue = 0
    var state = previousState ?? defaultValue

    switch action {
        /// Handling an action implemented as a struct
        case let action as IncrementAction:
            return state + action.payload
        // Handling actions implemented as Enums
        case CountEnumAction.Increment:
            return AppState(count: state.count + 1)
        case CountEnumAction.Decrement:
            return AppState(count: state.count - 1)
        case CountEnumAction.Set(let value):
           return AppState(count: value)


        default:
            return state
    }
}

/**
 The applications state. This should contain the state of the whole application.
 When building larger applications, you can optionally assign complex structs to properties on the
 AppState and handle them in the part of the application that uses them.
 */
struct AppState {
    var count: Int!
}

/**
 Create the applications reducer. While we could create a combineReducer function we've currently
 chosen to allow reducers to be statically typed and accept static states - instead of Any - which
 currently forces us to define the application reducer as such. This could possibly be simplified
 with reflection.
 */
let applicationReducer = {(state: AppState? = nil, action: Action) -> AppState in

    return AppState(
        count: counterReducer(state?.count, action: action),
    )
}

// Create application store. The second parameter is an optional default state.
let store = createStore(applicationReducer, nil)

let disposable = store.subscribe { state in
    print(state)
}


store.dispatch(IncrementAction())
// {counter: 1}

store.dispatch(CountEnumAction.Increment)
// {counter: 2}

store.dispatch(CountEnumAction.Decrement)
// {counter: 1}

// Dispose of the subscriber after use.
disposable.dispose()

License

MIT

Credits

Aleksander Herforth Rendtslev - @arendtslev
Karl Bowden - @karlbowden