一个 Swift 包,用于使用 The Composable Architecture 处理可加载项。
使用 swift package manager
将此包安装到您的项目中。
let package = Package(
...
dependencies: [
...
.package(url: "https://github.com/m-housh/swift-tca-loadable.git", from: "0.2.0")
]
...
)
0.3.+ 版本引入了与之前版本的不兼容性变更。 0.3.*
版本更新为使用 composable architecture 中的 Reducer
。
此包提供了一个 LoadableView
以及几种在您的 Reducer
实现中使用的类型。
下面显示了一个示例 Reducer
,并使用了 LoadableView
。
import ComposableArchitecture
import Loadable
import SwiftUI
struct App: Reducer {
struct State: Equatable {
@LoadableState var int: Int?
}
enum Action: Equatable, LoadableAction {
case loadable(LoadingAction<Int>)
}
@Dependency(\.continuousClock) var clock;
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .loadable(.load):
return .load {
/// sleep to act like data is loading from a remote.
try await clock.sleep(for: .seconds(2))
return 42
}
case .loadable:
return .none
}
}
.loadable(state: \.$int)
}
}
struct ContentView: View {
let store: StoreOf<App>
var body: some View {
VStack {
LoadableView(store: store.scope(state: \.$int, action: Preview.Action.int)) {
WithViewStore($0, observe: { $0 }) { viewStore in
Text("Loaded: \(viewStore.state)")
}
Button(action: { ViewStore(store).send(.load) }) {
Text("Reload")
}
.padding(.top)
}
.padding()
}
}
上述代码在项目处于 notRequested
或 isLoading
状态时使用默认的 ProgressView
,但您可以覆盖每个视图。
struct ContentView: View {
let store: StoreOf<App>
var body: some View {
LoadableView(
store: store.scope(state: \.$score, action: App.Action.int)
) { scoreStore in
// The view when we have loaded content.
WithViewStore(scoreStore) { viewStore in
Text("Your score is: \(viewStore.state)")
}
} isLoading: { (isLoadingStore: Store<Int?, App.Action>) in
MyCustomIsLoadingView(store: isLoadingStore)
} notRequested: { (notRequestedStore: Store<Void, App.Action>) in
MyCustomNotRequestedView(store: notRequestedStore)
}
}
}
您可以在这里查看 API 文档。