Elementary

Elementary 是一个实验性的、单向的和纯函数式的 Swift 架构。它的灵感来源于 ELM 和 Redux。其背后的主要动机是 SwiftUI 的引入,但这个核心包不依赖于 Combine 或 SwiftUI。

安装

当使用 Swift 包管理器时,请使用 Xcode 11+ 安装,或将以下行添加到您的依赖项中

.package(url: "https://github.com/mkj-is/Elementary.git", from: "0.1.0")

扩展

用于构建 SwiftUI 应用的基础扩展是 ElementaryCombine。如果您仅支持最新的 Apple 操作系统,请毫不犹豫地使用这个扩展。

另一个真正实验性的扩展是 ElementaryEffectBuilder。这个扩展用于使用新的 Swift 函数构建器组合副作用。

用法

所有内容都通过使用以下组件初始化 Store 绑定在一起

示例

让我们来看第一个例子:一个计数器的简单实现,用户可以对其进行递增、递减和重置。

首先,我们需要定义所有的 actions。在这种情况下,一些枚举就足够了

enum CounterAction {
    case increment, decrement, reset
}

然后我们实现接受 state 和 action 并更新 state 的函数。这里唯一应该发生的事情是改变 state。

func updateCounter(state: inout Int, action: CounterAction) {
    switch action {
    case .increment:
        state += 1
    case .decrement:
        state = max(0, state - 1)
    case .reset:
        state = 0
    }
}

我们最后需要做的是初始化 store。这段代码正是这样做的,并模拟了应用程序的示例运行。可测试性是这种分解的关键特性之一,您可以在示例test cases中亲自查看。

let store = Store(state: 0, update: updateCounter)
store.dispatch(.increment)
store.dispatch(.increment)
store.dispatch(.decrement)
store.dispatch(.increment)
store.dispatch(.reset)
store.state

Effects

大多数客户端应用程序需要执行一些异步工作。让我们以简单的秒表为例,它每秒递增 state。

enum StopwatchAction {
    case start, stop, increment, reset
}


func updateStopwatch(state: inout Int, action: StopwatchAction) {
    switch action {
    case .reset:
        state = 0
    case .increment:
        state += 1
    case .start, .stop:
        break
    }
}

现在我们已经定义了所有的 actions 和 update function。下一步是编写一个函数,该函数返回带有 timer 捕获值的新副作用。该 effect 将仅对两个 actions 做出反应:start 和 stop。当这些 actions 被 dispatch 时,timer 将被启动或停止。DispatchSourceTimer 用于使此代码具有多平台和向后兼容性。

func createStopwatchEffect() -> Effect<Int, StopwatchAction> {
    var timer: DispatchSourceTimer?
    return { _, action, dispatch in
        switch action {
        case .start:
            timer = DispatchSource.makeTimerSource()
            timer?.schedule(deadline: .now() + 1, repeating: 1)
            timer?.setEventHandler {
                dispatch(.increment)
            }
            timer?.resume()
        case .stop, .reset:
            timer = nil
        case .increment:
            break
        }
    }
}

贡献

欢迎所有贡献。

项目由 Matěj Kašpar Jirásek 创建。

项目根据 MIT license 获得许可。