ReduxKit 0.1.4

ReduxKit 0.1.4

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2015年12月
SPM支持 SPM

Karl Bowden 维护。



ReduxKit 0.1.4

  • 作者:
  • Aleksander Herforth Rendtslev 和 Karl Bowden

ReduxKit

跨推广 / 授粉

#13: @Ben-G 已经独立开发了一个非常严谨、非常Swift风格的 Redux 实现作为 Swift-Flow

经过短暂讨论,双方都同意合作和共享想法将对两个项目都有益处。去看看吧。欢迎对这两个项目的反馈。

介绍

ReduxKit 是 Dan Abramov 和 React 社区使用的 JavaScript Redux 库的 Swift 实现。ReduxKit 尽可能地接近 Redux,同时适当地引入 Swift 的做事方式。

有关框架的详细说明可以在官方 Redux 仓库中找到: Redux

ReduxKit 目前已在一些 Swift 应用程序中实现,并且经常更新。非常期待添加、中间件和帮助!所以如果您正在尝试它并且有任何建议 - 随时欢迎提出问题,我会及时回复。

安装

主要内容

原始 gist 的一个更高级的 Swift 示例

import ReduxKit

/**
  * This is a simple standard action. The only requirement is that an action complies to
  * the Action protocol. The SimpleStandardAction contains a strongly typed rawPayload
  * property. The protocol automatically assigns the rawPayload to the Actions payload
  * property. This removes the necessity of type casting whenever working with actions in
  * a reducer.
  *
  * There's also the StandardAction protocol, that requires the struct to have an
  * initializer. This is required if the bindActionCreators helper is to be used.
  */
struct IncrementAction: SimpleStandardAction {
    let meta: Any? = nil
    let error: Bool = false
    let rawPayload: Int = 1
}

struct DecrementAction: SimpleStandardAction {
    let meta: Any? = nil
    let error: Bool = false
    let rawPayload: Int = 1
}

/**
  * 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 actions.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 {
        case let action as IncrementAction:
            return state + action.rawPayload
        case let action as DecrementAction:
            return state - action.rawPayload
        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(IncrementAction())
// {counter: 2}

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

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

类型和通用的状态

ReduxKit 在简单的实现和使用方面大量使用了 Swift 泛型。

作为泛型使用的类型只有 StateActionPayloadType。其中只有 State 没有推断,并且会被频繁使用。由于 typealias 不支持泛型,这会导致框架源代码更难阅读。示例 typealias 已在源代码中内部包含。

一旦在您的项目中定义了根状态类型,您可能需要声明适当的 typealias 以映射到 JavaScript Redux 类型。

// These two are already exported by ReduxKit as they do not use the State generic
// typealias Dispatch = Action -> Action
// typealias DispatchTransformer = Dispatch -> Dispatch

struct State {} // Can be named anything you like, as long as it's consistent in the typealias declarations

// Underscores are used where needed to prevent clashes with exported protocols. Again, naming is up to you.

typealias Store = ReduxKit.Store<State>

typealias Reducer = (previousState: State?, action: Action) -> State
typealias Subscriber = (updatedState: State) -> ()

typealias MiddlewareApi = Store
typealias Middleware = MiddlewareApi -> DispatchTransformer
typealias StoreCreator = (reducer: Reducer, initialState: State?) -> Store
typealias StoreEnhancer = (StoreCreator) -> StoreCreator

typealias StateStream = ReduxKit.StateStream<State>
typealias StreamFactory = (initialState: State) -> StateStream

applyMiddleware 函数中可以看到不支持的泛型,这是扩展 ReduxKit 示例的最佳例子。

// How the applyMiddleware function would ideally be declared
func applyMiddleware(middleware: [Middleware])
    -> StoreEnhancer

// Expanding out (sans generic state):
func applyMiddleware(middleware: [MiddlewareApi -> DispatchTransformer])
    -> StoreCreator
    -> StoreCreator

func applyMiddleware(middleware: [Store -> DispatchTransformer])
    -> ((Reducer, State?) -> Store)
    -> ((Reducer, State?) -> Store)

func applyMiddleware(middleware: [Store -> DispatchTransformer])
    -> (((State?, Action) -> State, State?) -> Store)
    -> (((State?, Action) -> State, State?) -> Store)

// With the generic State
func applyMiddleware<State>(middleware: [(Store<State>) -> DispatchTransformer])
    -> (((State?, Action) -> State, State?) -> Store<State>)
    -> (((State?, Action) -> State, State?) -> Store<State>)

API

简化版和实际公共函数和类型

创建 Store

createStore(reducer: Reducer, state: State?) -> Store
createStore<State>(reducer: (State?, Action) -> State, state: State?) -> Store<State>

创建流式存储

createStreamStore(streamFactory: StreamFactory, reducer: Reducer, state: State?) -> Store
createStreamStore<State>(
    streamFactory: State -> StateStream<State> = createSimpleStream,
    reducer: (State?, Action) -> State,
    state: State?)
    -> Store<State>

createStreamStore(streamFactory: StreamFactory) -> StoreCreator
createStreamStore<State>(streamFactory: State -> StateStream<State>)
    -> (reducer: (State?, Action) -> State, state: State?)
    -> Store<State>

可丢弃的

protocol ReduxDisposable {
    var disposed: Bool { get }
    var dispose: () -> () { get }
}

struct SimpleReduxDisposable: ReduxDisposable {
    init(disposed: () -> Bool, dispose: () -> ())
}

状态流

struct StateStream {
    let dispatch: State -> ()
    let subscribe: Subscriber -> ReduxDisposable
    let getState: () -> State
    init(dispatch: State -> (), subscribe: Subscriber -> ReduxDisposable, getState: () -> State)
}
struct StateStream<State> {
    let dispatch: State -> ()
    let subscribe: (State -> ()) -> ReduxDisposable
    let getState: () -> State
    init(dispatch: State -> (), subscribe: (State -> ()) -> ReduxDisposable, getState: () -> State)
}

存储类型

protocol StoreType {
    typealias State
    var dispatch: Dispatch { get }
    var subscribe: (Subscriber) -> ReduxDisposable { get }
    var getState: () -> State { get }
    init(dispatch: Dispatch, subscribe: (Subscriber) -> ReduxDisposable, getState: () -> State)
}

存储

struct Store<State>: StoreType {
    let dispatch: Dispatch
    let subscribe: (Subscriber) -> ReduxDisposable
    let getState: () -> State
    var state: State
    init(dispatch: Dispatch, subscribe: (Subscriber) -> ReduxDisposable, getState: () -> State)
}

应用中间件

func applyMiddleware(middleware: [Middleware]) -> StoreEnhancer
func applyMiddleware<State>(middleware: [Store<State> -> DispatchTransformer])
    -> (((State?, Action) -> State, State?) -> Store<State>)
    -> (((State?, Action) -> State, State?) -> Store<State>)

绑定动作创建器

func bindActionCreators<Action where Action: StandardAction>(type: Action.Type, dispatch: Dispatch)
    -> (payload: Action.PayloadType?)
    -> ()

可用的中间件

状态流

ReduxKit 存储在本质上,是一种可订阅的状态流。你可能已经从响应式框架中熟悉了这个概念。事实上,这两者非常相似,你可能会更愿意使用 ReduxKit 与你喜欢的响应式框架一起使用。

状态流类型正好允许这样做。结合状态流工厂,它允许 ReduxKit 使用几乎任何现有响应式框架作为状态流。

ReduxKit 中包含了一个状态流。不推荐将其用于任何需要更多的情况,因为它不是线程安全或泄漏安全的。SimpleStateStream 只是一个订阅者数组。

ReduxKit 为以下提供了状态流绑定:

待办事项:包括示例和链接到响应式流提供程序。

你怎么能帮忙呢?

我希望 ReduxKit 的中间件能够得到顺利的实施,以便我们能在将来改变我们做 iOS 开发的方式。因此,我欢迎使用拉取请求、功能请求和建议。我希望这个库能变得尽可能好,而我只有通过大家的帮助才能实现这一点。

待办事项

ReduxKit 的实际实现相当完整。但仍然需要更多的工具。

  • 测试和发布响应式框架绑定
  • 创建 TODO 应用程序以展示易用性
  • 文档:我们应该做得有多全面?Dan 的文档已经很好地描述了核心原则。
  • 开发工具。这里是 Redux 的真正力量所在 — 在测试中撤销状态将使开发和调试变得更加容易。

许可协议

MIT