All Projects → lsunsi → ReduxSwift

lsunsi / ReduxSwift

Licence: MIT license
Predictable state container for Swift too

Programming Languages

swift
15916 projects
objective c
16641 projects - #2 most used programming language

Projects that are alternatives of or similar to ReduxSwift

vue-unstated
A tiny state management library for Vue Composition API.
Stars: ✭ 30 (-21.05%)
Mutual labels:  state-management
vuex-module-generator
abdullah.github.io/vuex-module-generator
Stars: ✭ 89 (+134.21%)
Mutual labels:  state-management
incubator-eventmesh
EventMesh is a dynamic event-driven application runtime used to decouple the application and backend middleware layer, which supports a wide range of use cases that encompass complex multi-cloud, widely distributed topologies using diverse technology stacks.
Stars: ✭ 939 (+2371.05%)
Mutual labels:  state-management
use-app-state
🌏 useAppState() hook. that global version of setState() built on Context.
Stars: ✭ 65 (+71.05%)
Mutual labels:  state-management
use-query-string
🆙 A React hook that serializes state into the URL query string
Stars: ✭ 50 (+31.58%)
Mutual labels:  state-management
react-zeno
The React companion to Zeno, a Redux implementation optimized for Typescript.
Stars: ✭ 14 (-63.16%)
Mutual labels:  state-management
react-evoke
Straightforward action-driven state management for straightforward apps built with Suspense
Stars: ✭ 15 (-60.53%)
Mutual labels:  state-management
flutter expense manager
Flutter Provider and Shared Preferences Sample Application.
Stars: ✭ 59 (+55.26%)
Mutual labels:  state-management
store keeper
StoreKeeper is an easy and flexible state management system for Flutter apps
Stars: ✭ 22 (-42.11%)
Mutual labels:  state-management
teaful
🍵 Tiny, easy and powerful React state management
Stars: ✭ 638 (+1578.95%)
Mutual labels:  state-management
concave
🧐 Lens-like state management (for React).
Stars: ✭ 13 (-65.79%)
Mutual labels:  state-management
aurelia-hoc-store
An Aurelia application showing the use of higher order components and a single state approach.
Stars: ✭ 20 (-47.37%)
Mutual labels:  state-management
stook
A minimalist design state management library for React.
Stars: ✭ 86 (+126.32%)
Mutual labels:  state-management
kstatemachine
KStateMachine is a Kotlin DSL library for creating finite state machines (FSM) and hierarchical state machines (HSM).
Stars: ✭ 63 (+65.79%)
Mutual labels:  state-management
jedisdb
redis like key-value state management solution for React
Stars: ✭ 13 (-65.79%)
Mutual labels:  state-management
solid-zustand
🐻 State management in Solid using zustand.
Stars: ✭ 44 (+15.79%)
Mutual labels:  state-management
reactube-client
A clone Youtube Web Player using React Provider Pattern, React Context and Typescript
Stars: ✭ 92 (+142.11%)
Mutual labels:  state-management
statebot-sh
Statebot for shell-scripts. Write more robust and understandable programs.
Stars: ✭ 14 (-63.16%)
Mutual labels:  state-management
ReduRx
👌 A thin layer of a Redux-based state manager on top of RxDart
Stars: ✭ 41 (+7.89%)
Mutual labels:  state-management
Airstream
State propagation and event streams with mandatory ownership and no glitches
Stars: ✭ 160 (+321.05%)
Mutual labels:  state-management

ReduxSwift

ReduxSwift is a minimal Swift port of Redux, a popular JavaScript library for application state management.

Swift version Carthage compatible Platforms Release License

Functionality
  • Centralized State
  • Unidirectional Data Flow
  • Functional Reactive Programming
Implementation
  • Type Safe
  • Extensible
  • Unobtrusive

Getting Started

"The whole state of your app is stored in an object tree inside a single store. The only way to change the state tree is to emit an action, an object describing what happened. To specify how the actions transform the state tree, you write pure reducers. That's it!" - Redux's Documentation

Application State

The Application State is a container that stores all information needed for your app to render. Since it's only a data container, it can be of any type from a single Int to a complex Struct.

struct AppState {
    struct Todo {
        let text: String
        var done: Bool
    }

    var todos: [Todo] = []
}
Tips
  • Structs are recommended for complex state structures, since they guarantee the reducer can't modify the state directly
  • State should be as minimal as possible, which means cheaply derivable data should be excluded from it

Actions

Actions are structs that describe changes to be made to the Application State. Since actions are the only way to change it, the action set represents all ways your app can change its own state. The only requirement for your action types are that they follow the ActionType protocol.

struct ADD_TODO: ActionType {
    let text: String
}

struct DO_TODO: ActionType {
    let id: Int
}

struct CLEAN_DONE: ActionType {

}
Tips
  • Although classes can be used to define Actions as well, little data containers like that benefit from the pass-by-value behavior offered by structs
  • Actions should carry all information needed by the reducer to make the actual change (more on that next).

Reducers

Reducers are pure functions that take an action and the current state (if any), and return a new state. Reducers are required to initialize the state in case of absence and must always return a state instance. Since these functions must be pure, all data needed for the change to be made have to be included in the action struct.

func reducer(action: ActionType, state: AppState?) -> AppState {
    var state = state ?? AppState.init()

    switch action {

    case let a as ADD_TODO:
        let todo = AppState.Todo(text: a.text, done: false)
        state.todos.append(todo)

    case let a as DO_TODO:
        state.todos[a.id].done = true

    case _ as CLEAN_DONE:
        let todos = state.todos.filter{!$0.done}
        state.todos = todos

    default: break
    }

    return state
}
Tips
  • Reducers can be composed together, making it possible to modularize your state architecture
  • Reducers cannot have side-effects, so if you need asynchronous action dispatching you might need to check out some middleware for it

Fire it up

The State, Actions and Reducers come together in the Store creation. It exposes the current state through the 'state' property and a single method 'dispatch' used for dispatching actions.

let store = Store<AppState>.init(reducer: reducer, state: nil, middlewares: [])

// State.todos => []
store.dispatch(ADD_TODO(text: "Code some Swift!"))
// State.todos => [{text "Code some Swift!", done false}]
store.dispatch(ADD_TODO(text: "Code more Swift!"))
// State.todos => [{text "Code some Swift!", done false}, {text "Code more Swift!", done false}]
store.dispatch(DO_TODO(id: 0))
// State.todos => [{text "Code some Swift!", done true}, {text "Code more Swift!", done false}]
store.dispatch(CLEAN_DONE())
// State.todos => [{text "Code more Swift!", done false}]
Tips
  • The Store can be initialized with a State, making it easy to save and restore it
  • Middlewares can be used to enhance the Store functionality (more on that next)

Going deeper

You just learned about the core concepts of the Redux architecture. Next we'll talk about two middlewares included in this framework that extend the store functionality to help you integrate it in your application.

Subscriptions

Everything we learned until now would be pointless if you didn't have a way to get notified about state changes whenever they happen. This middleware lets you do that in a cool reactive programming way.

let subs = Subscriptions<AppState, Int>.init()
let subsStore = Store<AppState>.init(reducer: reducer, state: nil, middlewares: [subs.middleware])

subs.subscribe(key: 1) {state in
    print("state changed!")
}

subs.unsubscribe(key: 1)
Tips
  • Your subscriber id can be of whatever Hashable type, as long as you identify it as the second generic parameter (Int in the previous example)
  • Did you know UIView's are Hashable?

Thunk

This is a basic middleware that enables asynchronous dispatching. It works alongside an action type called THUNK, that takes a function that takes the Store as it's first parameter. That way you can dispatch an function that will be responsible for dispatching other actions.

let thunk = Middlewares<AppState>.thunk
let thunkStore = Store<AppState>.init(reducer: reducer, state: nil, middlewares: [thunk])

thunkStore.dispatch(THUNK<AppState>{store in
    _ = store.dispatch(CLEAR_DONE())
})
Tips
  • Your thunk function can use the store reference however they want, including through in background routines
  • Thunks are just a basic way of inverting the control flow of the Store. For complex asynchronous workflows you might need to check elsewhere.

Logger

This middleware is a developer helper that logs action and state in down and up stream through the middleware chain. That means it will print to console all actions dispatched and the states before and after they were reduced.

let logger = Middlewares<AppState>.logger
let loggedStore = Store<AppState>.init(reducer: reducer, state: nil, middlewares: [logger])

Installation

Carthage

This is the recommended way of installing this package.

Carthage is an awesome dependency manager that'll take care of your dependencies without getting in your way. To install ReduxSwift through Carthage, just follow these steps:

  • Add the following line to your Cartfile
github "lsunsi/ReduxSwift"
  • Run the following command to fetch and build your dependencies
$ carthage update
  • Drag the compiled framework from the Carthage folder into your project
  • Rejoice!

Manually

If you prefer to install this package manually, just follow these steps:

  • Make sure your project is a git repository. If it isn't, just run this command from your project root folder:
$ git init
  • Add ReduxSwift as a git submodule by running the following command.
$ git submodule add https://github.com/lsunsi/ReduxSwift.git
  • Drag the ReduxSwift.xcodeproj from the newly created ReduxSwift folder to your project.

It should be nested in your actual project in the Project Navigator.

  • Add ReduxSwift to your Embedded Binaries.

Select your project from the Project Navigator. Then, select your Target and you'll see an Embedded Binaries menu in the General tab.

  • Rejoice!

License

This project is licensed under the MIT License - see the LICENSE file for details

Acknowledgments

  • Dan Abramov for bringing Redux to our lives
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].