{"id":15561338,"url":"https://github.com/svdo/rerxswift","last_synced_at":"2025-04-14T19:08:00.000Z","repository":{"id":52672783,"uuid":"100500550","full_name":"svdo/ReRxSwift","owner":"svdo","description":"ReRxSwift: RxSwift bindings for ReSwift","archived":false,"fork":false,"pushed_at":"2022-04-06T06:36:59.000Z","size":2296,"stargazers_count":99,"open_issues_count":2,"forks_count":16,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-14T19:07:50.346Z","etag":null,"topics":["frp","functional-reactive-programming","reactive-programming","reswift","rxswift","swift4"],"latest_commit_sha":null,"homepage":"https://svdo.github.io/ReRxSwift","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/svdo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-16T14:50:37.000Z","updated_at":"2024-09-07T11:06:46.000Z","dependencies_parsed_at":"2022-08-22T03:40:41.482Z","dependency_job_id":null,"html_url":"https://github.com/svdo/ReRxSwift","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svdo%2FReRxSwift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svdo%2FReRxSwift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svdo%2FReRxSwift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svdo%2FReRxSwift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/svdo","download_url":"https://codeload.github.com/svdo/ReRxSwift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943456,"owners_count":21186958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["frp","functional-reactive-programming","reactive-programming","reswift","rxswift","swift4"],"created_at":"2024-10-02T16:07:30.870Z","updated_at":"2025-04-14T19:07:59.982Z","avatar_url":"https://github.com/svdo.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ReRxSwift\n![Swift Version 4.1](https://img.shields.io/badge/Swift-v4.1-yellow.svg)\n[![Build Status](https://travis-ci.org/svdo/ReRxSwift.svg?branch=master)](https://travis-ci.org/svdo/ReRxSwift)\n[![API Documentation](https://svdo.github.io/ReRxSwift/badge.svg)](https://svdo.github.io/ReRxSwift)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![CocoaPods Version Badge](https://img.shields.io/cocoapods/v/ReRxSwift.svg)](https://cocoapods.org/pods/ReRxSwift)\n![Supported Platforms Badge](https://img.shields.io/cocoapods/p/ReRxSwift.svg)\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/svdo/ReRxSwift/blob/master/LICENSE)\n\n*[RxSwift][1] bindings for [ReSwift][2]*\n\n## Table of Contents\n\n* [Introduction](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n* [API](#api)\n  - [Connectable](#connectable)\n  - [Connection](#connection)\n- [Example App](#example-app)\n- [FAQ](#faq)\n\n\n## Introduction\n\nIn case you don't know them yet, these are two awesome frameworks:\n\n- [ReSwift][2] is a small framework that implement the\n  [unidirectional data flow architecture][3] in Swift. It is inspired\n  by the JavaScript implementation of that architecture: [Redux][4].\n- [RxSwift][1] is a Swift implementation of [ReactiveX][5]. Amongst\n  other things, it allows you to easily bind properties to user interface\n  elements.\n\nUsing those two frameworks you can make very nice app architectures.\nRxSwift allows you to bind application state to your UI, and ReSwift\nemits state updates in response to actions. We take it one step further\nthough.\n\nSimilar to [react-redux][6], ReRxSwift allows you to create view\ncontrollers that have `props` and `actions`. View controllers read all\ndata they need from their `props` (instead of directly from the state),\nand they change data by invoking callbacks defined by `actions` (instead\nof directly dispatching ReSwift actions). This has some nice advantages:\n\n- Better separation of concerns. It is easier to understand what your\n  view controller does and what data it uses. In other words, it\n  facilitates local reasoning.\n- Unit-testing. Because of the separation of concerns, you can easily\n  unit-test your view controllers, all the way up to the Interface\n  Builder connections.\n- Better reusability. Reusing your view controllers is as simple as\n  specifying different mappings from state to `props` and from ReSwift\n  actions to `actions`. (See also section 'Open Issues' below.)\n- Rapid prototyping. You can easily use dummy `props` and `actions` so\n  that you get a working UI layer prototype. Without writing any of your\n  application's business logic, you can implement your presentation\n  layer in such a way that it is very simple to replace the dummies\n  with real state and actions.\n\n\n## Installation\n\nThe easiest way to use this library is through [Cocoapods][15] or [Carthage][16]. For CocoaPods, add this to your `Podfile`:\n\n```ruby\npod 'ReRxSwift', '~\u003e 2.0'\n```\n\nFor Carthage, add this to your `Cartfile`:\n\n```\ngithub \"svdo/ReRxSwift\" ~\u003e 2.0\n```\n\n## Usage\n\nThis section assumes that there is a global variable `store` that contains\nyour app's store, and that it's type is `Store\u003cAppState\u003e`. You have a view\ncontroller that manages a text field; the text field displays a value from\nyour state, and on `editingDidEnd` you trigger an action to store the text\nfield's content back into your state. To use ReRxSwift for your view\ncontroller `MyViewController`, you use the following steps.\n\n1. Create an extension to your view controller to make it `Connectable`,\n   defining the `Props` and `Actions` that your view controller needs:\n\n    ```swift\n    extension MyViewController: Connectable {\n        struct Props {\n            let text: String\n        }\n        struct Actions {\n            let updatedText: (String) -\u003e Void\n        }\n    }\n    ```\n\n2. Define how your state is mapped to the above `Props` type:\n\n    ```swift\n    private let mapStateToProps = { (appState: AppState) in\n        return MyViewController.Props(\n            text: appState.content\n        )\n    }\n    ```\n\n3. Define the actions that are dispatched:\n\n    ```swift\n    private let mapDispatchToActions = { (dispatch: @escaping DispatchFunction) in\n        return MyViewController.Actions(\n            updatedText: { newText in dispatch(SetContent(newContent: newText)) }\n        )\n    }\n    ```\n\n4. Define the connection and hook it up:\n\n    ```swift\n    class MyViewController: UIViewController {\n        @IBOutlet weak var textField: UITextField!\n\n        let connection = Connection(\n            store: store,\n            mapStateToProps: mapStateToProps,\n            mapDispatchToActions: mapDispatchToActions\n        )\n\n        override func viewWillAppear(_ animated: Bool) {\n            super.viewWillAppear(animated)\n            connection.connect()\n        }\n\n        override func viewDidDisappear(_ animated: Bool) {\n            super.viewDidDisappear(animated)\n            connection.disconnect()\n        }\n    }\n    ```\n\n5. Bind the text field's text, using a Swift 4 key path to refer to the\n   `text` property of `Props`:\n\n    ```swift\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        connection.bind(\\Props.text, to: textField.rx.text)\n    }\n    ```\n\n6. Call the action:\n\n    ```swift\n    @IBAction func editingChanged(_ sender: UITextField) {\n        actions.updatedText(sender.text ?? \"\")\n    }\n    ```\n\nThis is pretty much the [`SimpleTextFieldViewController`][10] inside the sample\napp. That view controller comes with complete unit tests:\n[`SimpleTextFieldViewControllerSpec`][11].\n\n\n## API\n\nBelow is a high-level description of the most important components of the API.\nThere is also [full API documentation of ReRxSwift][14] available.\n\n### Connectable\n\nThis is the protocol that your view controller has to conform to. It requires\nyou to add a `connection` property. It provides the `props` and `actions` that\nyou can use in your view controller. Normally, you declare the `connection` as\nfollows:\n\n```swift\nclass MyViewController: Connectable {\n    let connection = Connection(\n        store: store,\n        mapStateToProps: mapStateToProps,\n        mapDispatchToActions: mapDispatchToActions\n    )\n}\n```\n\nRefer to the `Connection` constructor documentation for more information.\n\n#### props\nThis contains the `Props` object that you create using `mapStateToProps`. In\nother words: it contains all data that your view controller uses, automatically\nextracted from your application state. When using the `bind` methods in\n`Connection`, you probably don't need to use this `props` property directly.\n\n#### actions\nThis contains the `Actions` object that you create using `mapDispatchToActions`.\nIn other words: it specifies which ReSwift action has to be dispatched when\ncalling the callbacks defined by your `actions`.\n\n### Connection\nThe `Connection` takes care of the mapping from you application state to your\nview controller `props`, and of dispatching the mapped action when calling\nfunctions in your view controller `actions`.\n\n#### Constructor(store, mapStateToProps, mapDispatchToActions)\nTo create your `Connection` instance, you need to construct it with three\nparameters:\n\n- **store**: Your application's ReSwift store.\n- **mapStateToProps**: A function that takes values from your application's\n  state and puts them in the view controller's `props` object. This decouples\n  your application state from the view controller data.\n- **mapDispatchToActions**: A function that specifies which actions your view\n  controller can call, and for each of those which ReSwift action needs to be\n  dispatched.\n\n#### connect()\nCalling this method causes the connection to subscribe to the ReSwift store and\nreceive application state updates. Call this from your view controller's\n`viewWillAppear` or `viewDidAppear` method.\n\n#### disconnect()\nCalling this method causes the connection to unsubscribe from the ReSwift store.\nCall this from your view controller's `viewWillDisappear` or `viewDidDisappear`.\n\n#### subscribe(keyPath, onNext)\nSubscribe to an entry in your view controller's `props`, meaning that the given\n`onNext` handler will be called whenever that entry changes.\n\n#### bind(keyPath, to, mapping)\nThis function binds an entry in your view controller's `props` to a\nRxSwift-enabled user interface element, so that every time your `props` change,\nthe user interface element is updated accordingly, automatically.\n\nThe function `bind` takes the following parameters:\n- **keyPath**: The (Swift 4) key path that points to the element in your `props`\n  that you want to bind to the user interface element.\n- **to**: The RxSwift reactive property wrapper, e.g. `textField.rx.text` or\n  `progressView.rx.progress`.\n- **mapping**: _Most of the `bind` variants_ (but not all of them) allow you to\n  provide a mapping function. This mapping function is applied to the `props`\n  element at the specified `keyPath`. You can use this for example for type\n  conversions: your `props` contains a value as a `Float`, but the UI element\n  requires it to be a `String`. Specifying the mapping `{ String($0) }` will\n  take care of that. [`SteppingUpViewController.swift`][12] contains an example\n  of a mapping function that maps a `Float` value to the selected index of\n  a segmented control.\n\nJust for your understanding: there are several variants of the `bind` function.\nThey are all variants of this simplified code:\n\n```swift\nself.props\n    .asObservable()\n    .distinctUntilChanged { $0[keyPath: keyPath] == $1[keyPath: keyPath] }\n    .map { $0[keyPath: keyPath] }\n    .bind(to: observer)\n    .disposed(by: disposeBag)\n```\n\n## Example App\nThe folder [`Example`][13] contains the following examples:\n\n- **SimpleTextField**: Most basic use case of ReRxSwift, containing a text field that has its value bound, and an action.\n- **SteppingUp**: Use case with multiple bound values and actions, also showing how to transform values when binding them.\n- **TableAndCollection**: Shows how to use ReRxSwift in combination with RxSwift, RxCocoa and RxDataSources to have very simple table/collection views that automatically animate their updates.\n\n\n## FAQ\n\n### My `props` are not updated when the application state changes?\nThis happens when you forget to call `connection.connect()` in you view\ncontroller's `viewWillAppear` or `viewDidAppear` method. While you're at it,\nyou may want to verify that you also call `connection.disconnect()` in\n`viewWillDisappear` or `viewDidDisappear`.\n\n### I get compiler errors when calling `connection.bind()`?\nWhen calling `bind`, you pass a key path to an element in your `props` object.\nBecause of the way ReRxSwift makes sure to only trigger when this element\nactually changed, it compares its value with the previous one. This means\nthat the elements in your `props` object need to be `Equatable`. Simple types\nof course are already `Equatable`, but especially when binding table view\nitems or collection view items, you need to make sure that the types are\n`Equatable`.\n\nAnother common source of errors is when the type of the element in your `props`\ndoes not exactly match the expected type by the user interface element. For\nexample, you bind to a stepper's `stepValue`, which is a `Double`, but your\n`props` contains a `Float`. In these cases you can pass a mapping function as\nthe third parameter to `bind(_:to:mapping:)` to cast the `props` element to\nthe expected type. See [`SteppingUpViewController.swift`][12] for examples.\n\n### I double-checked everything and I still get errors!\nPlease open a [new issue][8] on GitHub, as you may have run into a bug. (But please make sure everything inside your `Props` type is `Equatable`!)\n\n\n[1]: https://github.com/ReactiveX/RxSwift\n[2]: https://github.com/ReSwift/ReSwift\n[3]: http://redux.js.org/docs/basics/DataFlow.html\n[4]: https://github.com/reactjs/redux\n[5]: http://reactivex.io\n[6]: http://redux.js.org/docs/basics/UsageWithReact.html\n[7]: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md\n[8]: https://github.com/svdo/ReRxSwift/issues\n[9]: https://github.com/svdo/ReRxSwift/issues/1\n[10]: https://github.com/svdo/ReRxSwift/blob/master/Example/SimpleTextField/SimpleTextFieldViewController.swift\n[11]: https://github.com/svdo/ReRxSwift/blob/master/ExampleTests/SimpleTextField/SimpleTextFieldViewControllerSpec.swift\n[12]: https://github.com/svdo/ReRxSwift/blob/master/Example/SteppingUp/SteppingUpViewController.swift\n[13]: https://github.com/svdo/ReRxSwift/tree/master/Example\n[14]: https://svdo.github.io/ReRxSwift\n[15]: http://cocoapods.org\n[16]: https://github.com/Carthage/Carthage\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvdo%2Frerxswift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsvdo%2Frerxswift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvdo%2Frerxswift/lists"}