Cloe 0.3.0

Cloe 0.3.0

Gil Birman维护。



Cloe 0.3.0

  • Gil Birman

Cloe

CI Status GitHub tag (latest SemVer) License

Cloe是针对SwiftUI的Redux在Combine上实现的解决方案,具有良好的设计风格。

设置您的store

struct AppState {
  var appName = "Demo App"
  var age = 6
  var names = ["hank", "cloe", "spike", "joffrey", "fido", "kahlil", "malik"]

  static let initialValue = AppState()
}

enum AppAction: Action {
  case growup
}

typealias AppStore = Store<AppReducer>

设置您的reducer

func appReducer(state: inout AppState, action: Action) {
  guard let action = action as? AppAction else { return }
  switch action {
  case .growup:
    state.age += 1
  }
}

实例化您的Store

// Create a store with the publisher middleware
// this middleware allows us to use `PublisherAction`
// later to dispatch an async action.
let store = AppStore(
  reducer: appReducer,
  state: .initialValue,
  middlewares: [createPublisherMiddleware()])

// Inject the store with `.environmentObject()`.
// Alternatively we could inject it with `.environment()`
let contentView = ContentView().environmentObject(store)

// later...
    window.rootViewController = UIHostingController(rootView: contentView)

(可选) 向store中添加一些便利扩展

这些扩展可以提高与store工作的便捷性。使用内建的 dispatch 函数,我们通常会使用 store.dispatch(AppAction.growup) 来发送。有了这个 dispatch 扩展,我们可以使用 store.dispatch(.growup) 来替代。

subscript 扩展允许我们在SwiftUI视图中避免使用闭包。例如,按钮可以使用以下方式实现:Button("Grow up", action: store[.growup])

extension Store {
  func dispatch(_ action: AppAction) {
    dispatch(action as Action)
  }

  subscript(_ action: AppAction) -> (() -> Void) {
    { [weak self] in self?.dispatch(action as Action) }
  }
}

将您的 SwiftUI 视图连接到您的 store

这是一个使用状态选择器注入状态的示例。我们在 View 中定义了状态选择器,但也可以在任何地方定义。

struct MyView: View {
  var index: Int

  // Define your derived state
  struct MyDerivedState: Equatable {
    var age: Int
    var name: String
  }

  // Inject your store
  @EnvironmentObject var store: AppStore

  // Connect to the store
  var body: some View {
    Connect(store: store, selector: selector, content: body)
  }

  // Render something using the selected state
  private func body(_ state: MyDerivedState) -> some View {
    Text("Hello \(state.name)!")
  }
  
  // Setup a state selector
  private func selector(_ state: AppState) -> MyDerivedState {
    .init(age: state.age, name: state.names[index])
  }
}

如果您想连接到 store 的状态而不定义选择器,则使用 ConnectStore。请注意,目前 ConnectStore 不会像 Connect 那样跳过重复的状态。

派发一个简单的动作

下面是如何派发一个简单动作的示例

    Button("Grow up") { self.store.dispatch(AppAction.growup) }
    
    // ... or ...
    
    Button("Grow up", action: store[AppAction.growup])

或者使用上面提到的可选的 Store 扩展

    Button("Grow up") { self.store.dispatch(.growup) }

    // ...or...

    Button("Grow up", action: store[.growup])

使用 publisher 中间件派发异步动作

下面是一个简单示例,更多关于 publisher 中间件的信息请参阅 此处

    Button("Grow up") { self.store.dispatch(self.delayedGrowup) }
    
  //...

  private let delayedGrowup = PublisherAction<AppState> { dispatch, getState, cancellables in
    Just(())
      .delay(for: 2, scheduler: RunLoop.main)
      .sink { _ in
        dispatch(AppAction.growup)
      }
      .store(in: &cancellables)
  }

使用 publisher-dispatcher 跟踪异步任务进度

publisher-dispatcher 文档.

与 ReSwift 有何不同?

  • ReSwift 经受战火考验。
  • ReSwift 正在实际的生产应用中使用。
  • Cloe 使用 Combine Publishers 而不是 定制的 StoreSubscriber
  • Cloe 的 Middleware 比的 ReSwift Middleware 简单,但实现了相同级别的灵活性。
  • Cloe的combineMiddleware函数更简洁、更容易阅读。
  • Cloe提供了一种流畅的方式来连接您的SwiftUI视图。
  • Cloe未为主Store状态提供跳过重复项的选项,但当您将其连接到SwiftUI组件时,它总是会跳过重复的状态(可能有所变化)。

为什么Store对象要遵守ObservableObject协议?

您可能已经注意到Cloe的Store类遵守了ObservableObject协议。然而,Store并不包含任何@Published属性。添加这种遵守只是为了方便使用.environmentObject()向您的store注入。然而,由于我们不暴露任何@Published变量,请不要期望当store发生变化时,带有

@ObservedObject var store: AppStore

的视图会自动重新渲染。这种设计是故意的,这样您就可以使用订阅通过Connect的更细粒度的更新。

示例

要运行示例项目,请克隆此存储库,然后从iOS Example目录打开iOS Example.xcworkspace。

要求

  • iOS 13
  • macOS 10.15
  • watchOS 6
  • tvOS 13

安装

使用Swift包管理器将此添加到您的项目中。在Xcode中,这很简单:File > Swift Packages > Add Package Dependency... 就完成了。以下是针对遗留项目的其他安装选项。

CocoaPods

如果你已经在使用 CocoaPods,只需将 'Cloe' 添加到你的 Podfile 中,然后运行 pod install

Carthage

如果你已经在使用 Carthage,只需将其添加到你的 Cartfile

github "gilbox/Cloe" ~> 0.3.0

然后运行 carthage update 来构建框架,并将构建的 Cloe.framework 拖入你的 Xcode 项目中。

许可证

Cloe 采用 MIT 许可证。更多详细信息请参阅 LICENSE 文件