Swiftpack.co - Package - StevenLambion/SwiftDux

SwiftDux

Predictable state management for SwiftUI applications.

Swift Version Platform Versions Github workflow codecov

Introduction

This is yet another redux inspired state management solution for swift. It's built on top of the Combine framework with hooks for SwiftUI. This library helps build applications around an elm-like architecture using a single, centralized state container. For more information about the architecture and this library, take a look at the getting started guide.

This library is designed around Combine and SwiftUI. For a more established library that doesn't require iOS 13, check out ReSwift.

Top Features

Redux-like State Management.

  • Middleware support
  • ActionPlan for action-based workflows.
    • Use them like action creators in Redux.
    • Supports async operations.
    • Supports returning a Combine publisher
  • OrderedState<_> for managing an ordered collection of state objects.

SwiftUI Integration.

  • @MappedState injects state into a view.
  • @MappedDispatch let's views dispatch actions.
    • Automatically updates the view after each sent action.
    • Supports action plans.
  • Connectable API connects and maps the application state into SwiftUI.
  • onAction(perform:) allows you to track or modify dispatched actions.
  • OrderedState<_> has direct support of List views.

Extras

  • PersistStateMiddleware to automatically persist and restore application state.
  • PrintActionMiddleware Simple middleware that prints out each dispatched action for debugging.

Documentation

Visit the documentation website.

Example

Todo Example App

Installation

Xcode 11

Use the new swift package manager integration to include the library.

Swift Package Manager

Include the library as a dependencies as shown below:

import PackageDescription

let package = Package(
  dependencies: [
    .Package(url: "https://github.com/StevenLambion/SwiftDux.git", majorVersion: 0, minor: 11)
  ]
)

SwiftUI Examples

Adding the SwiftDux store to the SwiftUI environment:

/// Basic store example

var store = Store(state: AppState(), reducer: AppReducer())

/// Advanced store example with middleware

var store = Store(
  state: AppState(),
  reducer: AppReducer(),
  middleware: [
    PrintActionMiddleware(),
    PersistStateMiddleware(JSONStatePersistor())
  ]
)

/// Inject the store

RootView().provideStore(store)

Inject the state into a view using property wrappers:

struct BookListView : View {

  @MappedState private var books: OrderedState<Book>
  @MappedDispatch() private var dispatch

  var body: some View {
    List {
      ForEach(books) { book in
        BookRow(title: book.title)
      }
      .onMove { self.dispatch(BookAction.move(from: $0, to: $1)) }
      .onDelete { self.dispatch(BookAction.delete(at: $0)) }
    }
  }
}

/// Adhere to the Connectable protocol to map a parent state to
/// one that the view requires.

extension BookListView : Connectable {

  func map(state: AppState) -> OrderedState<Book>? {
    state.books
  }

}

Update a view whenever an action is dispatched to the store.

extension BookListView : Connectable {

  /// Views always update when dispatching an action, but
  /// sometimes you may want it to update every time a given
  /// action is sent to the store.

  updateWhen(action: Action) -> Bool {
    action is BookStatusAction
  }

  func map(state: AppState) -> OrderedState<Book>? {
    state.books
  }

}

Modify actions sent from child views before they get to the store

struct AuthorView : View {

  @MappedState private var author: Author

  var body: some View {
    BookListContainer()
      .connect(with: author.id)
      .onAction { [author] action in
        if let action = action as? BookAction {
          return AuthorAction.routeBookAction(for: author.id, action)
        }
        return action
      }
  }

}

Github

link
Stars: 39
Help us keep the lights on

Dependencies

Used By

Total: 0

Releases

v0.11.2 - Oct 3, 2019

Changes

  • Cleanup to documentation. #13

Added

  • API to cancel publisher based ActionPlans. #14

Technical

  • Code formatting via swift-format. #13
  • Moved documentation to gh-pages branch. #13
  • Set up CI linting and testing via Github workflows. #13
  • Added code coverage reports via codecov. #13

v0.11.1 - Sep 19, 2019

Fixed

  • Fixed type erasing in StateConnectionViewGuard by returning the contents as an optional view rather than using AnyView.

v0.10.0 - Aug 30, 2019

Changes

  • PublishableActionPlan has been merged into ActionPlan.
  • All actions dispatched from a view will update that view. This includes actions dispatched inside an action plan.

Added

  • Middleware API
  • PrintActionMiddleware

v0.11.0 - Aug 30, 2019

Changes

  • Moved PrintActionMiddleware to SwiftDuxExtras
  • StoreProvider view modifier updates its view when a StoreAction<_> Is dispatched.

Added

  • SwiftDuxExtras module
  • Persistence API to SwiftDuxExtras
  • PersistStateMiddleware
  • StoreReducer for store specific actions.
  • "StoreAction<_>.prepare" action fired from the store at initialization.
  • "StoreAction<_>.reset(state:)" action to replace the current state of the store.

v0.9.0 - Aug 26, 2019

Changes

  • The view of a mapped state will wait to render until the state is exists (non-nil). This completes all the previous functionality of the Connector API.
  • The updateWhen argument of View.connect(updateWhen:mapState:) is now optional with a default value.

Fixed

  • Views continue to properly update when dispatching an acton after their parent view has re-rendered.

Removed

  • Connector API has been removed.