Skip to content

LoadableView

m-housh edited this page Aug 20, 2021 · 1 revision

LoadableView

A view that can handle loadable items using the ComposableArchitecture pattern. You will most likely want to make a more concrete view that fits your needs, using this internally.

public struct LoadableView<
  LoadedValue: Equatable,
  Action: Equatable,
  Failure: Error,
  NotRequestedView: View,
  LoadedView: View,
  ErrorView: View,
  IsLoadingView: View
>: View 

Although this looks pretty gnarly, it is not that bad from the call-site and allows customization of the views for each state of a Loadable item, and also includes sensible default views (i.e. ProgressView's) for when the item(s) are loading.

Example:

enum AppError: Error, Equatable {
  case loadingError
}

struct AppState: Equatable {
  var number: Loadable<Int, AppError> = .notRequested
}

enum AppReducer: Equatable {
  case load(LoadAction<Int, AppError>)
 }

let appReducer = Reducer<AppState, AppAction, LoadableEnvironment<Int, EmptyLoadRequest, AppError>>
  .empty.loadable(
    state: \.number,
    action: /AppAction.load,
    environment: { $0 }
  )

extension LoadableEnvironment where LoadedValue == Int, LoadRequest == EmptyLoadRequest, Failure == AppError {
  static let live = Self.init(
    load: { _ in
      Just(42)
        .setFailureType(to: AppError.self)
        .eraseToEffect()
    },
    mainQueue: .main
  )
}

struct MyLoadableNumberView: View {
  let store: Store<Loadable<Int, AppError>, LoadableAction<Int, AppError>>

  var body: some View {
    LoadableView(store: store, autoLoad: true) { store in
      WithViewStore(store) { viewStore in
        Text("\(viewStore.state)")
      }
    }
  }
}

let myView = MyLoadableNumberView(
  store: .init(
    initialState: .init(),
    reducer: appReducer,
    environment: .live
  )
)

Inheritance

View

Initializers

init(store:onLoad:autoLoad:loadedView:notRequestedView:isLoadingView:errorView:)

Create a loadable view.

public init(
    store: Store<Loadable<LoadedValue, Failure>, Action>,
    onLoad loadAction: Action,
    autoLoad: Bool = true,
    @ViewBuilder loadedView: @escaping (Store<LoadedValue, Action>) -> LoadedView,
    @ViewBuilder notRequestedView: @escaping (Store<Void, Action>) -> NotRequestedView,
    @ViewBuilder isLoadingView: @escaping (Store<LoadedValue?, Action>) -> IsLoadingView,
    @ViewBuilder errorView: @escaping (Store<Failure, Action>) -> ErrorView
  ) 

Parameters

  • store: The store to derive our state and actions from.
  • autoLoad: A flag for if we automatically send a load action if our state is .notRequested
  • loadedView: The view shown if our state is .loaded
  • notRequestedView: The view shown if our state is .notRequested
  • isLoadingView: The view shown if our state is .isLoading
  • errorView: The view shown if our state is .failed

Properties

store

The store to derive our state and actions from.

public let store: Store<Loadable<LoadedValue, Failure>, Action>

body

public var body: some View 

Methods

error(view:)

Replaces / overrides the error view.

public func error<V: View>(
    view: @escaping (Store<Failure, Action>) -> V
  ) -> LoadableView<LoadedValue, Action, Failure, NotRequestedView, LoadedView, V, IsLoadingView> 

Parameters

  • view: The new error view.

isLoading(view:)

Replaces / overrides the isLoading view.

public func isLoading<V: View>(
    view: @escaping (Store<LoadedValue?, Action>) -> V
  ) -> LoadableView<LoadedValue, Action, Failure, NotRequestedView, LoadedView, ErrorView, V> 

Parameters

  • view: The new is loading view.

loaded(view:)

Replaces / overrides the loaded view.

public func loaded<V: View>(
    view: @escaping (Store<LoadedValue, Action>) -> V
  ) -> LoadableView<LoadedValue, Action, Failure, NotRequestedView, V, ErrorView, IsLoadingView> 

Parameters

  • view: The new loaded view.

notRequested(view:)

Replaces / overrides the notRequested view.

public func notRequested<V: View>(
    view: @escaping (Store<Void, Action>) -> V
  ) -> LoadableView<LoadedValue, Action, Failure, V, LoadedView, ErrorView, IsLoadingView> 

Parameters

  • view: The new not requested view.
Clone this wiki locally