{"id":16699692,"url":"https://github.com/nalexn/minimalist","last_synced_at":"2025-03-17T00:33:52.664Z","repository":{"id":42145704,"uuid":"268254055","full_name":"nalexn/minimalist","owner":"nalexn","description":"Observable Property and Signal for building data-driven UI without Rx","archived":false,"fork":false,"pushed_at":"2023-04-12T05:41:25.000Z","size":33,"stargazers_count":93,"open_issues_count":2,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-03-15T00:46:50.332Z","etag":null,"topics":["combine-framework","data-driven","observer","observer-pattern","property-wrappers","reactive","reactiveswift","redux","rx","rxswift","signal"],"latest_commit_sha":null,"homepage":"","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/nalexn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-31T10:09:29.000Z","updated_at":"2024-08-21T20:02:15.425Z","dependencies_parsed_at":"2024-08-21T20:02:05.481Z","dependency_job_id":null,"html_url":"https://github.com/nalexn/minimalist","commit_stats":{"total_commits":20,"total_committers":2,"mean_commits":10.0,"dds":0.09999999999999998,"last_synced_commit":"2f609ebe2f334c98eb60750a5cb16495ecb15221"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fminimalist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fminimalist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fminimalist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fminimalist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nalexn","download_url":"https://codeload.github.com/nalexn/minimalist/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243835942,"owners_count":20355611,"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":["combine-framework","data-driven","observer","observer-pattern","property-wrappers","reactive","reactiveswift","redux","rx","rxswift","signal"],"created_at":"2024-10-12T18:07:55.136Z","updated_at":"2025-03-17T00:33:52.363Z","avatar_url":"https://github.com/nalexn.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Minimalist\n\n[![Build Status](https://travis-ci.com/nalexn/Minimalist.svg?branch=master)](https://travis-ci.com/nalexn/Minimalist) [![Coverage Status](https://coveralls.io/repos/github/nalexn/minimalist/badge.svg)](https://coveralls.io/github/nalexn/minimalist)\n\nBuilding data-driven UI without `Rx`\n\n---\n\nI'm a big fan of reactive frameworks. I've used RxSwift, ReactiveSwift, Combine, and I suffer every time I join the project where the team cannot adopt one for some reason.\n\n* Problem #1: Teams beware the complexity and steep learning curve\n* Problem #2: Traditional frameworks are too bulky for small projects\n\nThis library is a take on cutting off everything non-essential. In fact, all you need to build the data-driven UI is **observable property** and **event broadcaster**. And that's all that you get with this micro-framework (just 100 lines of code):\n\n### @Property\n\nAlso known as:\n\n* `BehaviorRelay` in RxSwift\n* `MutableProperty` in ReactiveSwift\n* `CurrentValueSubject` in Combine\n\n```swift\nclass ViewModel {\n    @Property var items: [Items] = []\n}\n\n// Access the current value:\nviewModel.items.count\n\n// Subscribe on changes of the value:\nviewModel.$items.observe(with: self) { (obj, items) in\n    ...\n}\n```\n\n### @Signal\n\nAlso known as:\n\n* `PublishRelay` in RxSwift\n* `Signal` in ReactiveSwift\n* `PassthroughSubject` in Combine\n\n```swift\nclass ViewModel {\n    @Signal var didReceiveMessage: Accepts\u003cMessage\u003e\n}\n\n// Broadcast a notification:\ndidReceiveMessage.send(message)\n\n// Subscribe on updates:\nviewModel.$didReceiveMessage.observe(with: self) { (obj, message) in\n    ...\n}\n```\n\n## Features\n\n### Access control\n\nYou can restrict the write access from outside of the module using just Swift's access control:\n\n```swift\nclass ViewModel {\n    @Property private(set) var value: String = \"Minimalist\"\n    @Signal private(set) var signal: Accepts\u003cVoid\u003e\n}\n\n// Cannot change property or trigger a signal:\nviewModel.value = \"abc\" // ❌\nviewModel.signal.send(()) // ❌\n```\n\n### Automatic memory management\n\nSubscription is bound to the lifetime of the supplied object and gets detached automatically. That object is also provided in the callback along with the value, so you don't need to do the `[weak self]` dance all the time:\n\n```swift\nclass ViewController: UIViewController {\n    var tableView: UITableView\n    \n    func viewDidLoad() {\n        ...\n        viewModel.$items.observe(with: self) { (vc, items) in\n            vc.tableView.reloadData()\n        }\n    }\n}\n```\n\n### Filter state updates (Redux)\n\nData-driven UI works best with unidirectional data flow design, which may involve using a centralized state in the app.\n\nUpon subscription, you can specify the `KeyPath` to the value inside the state container to receive scoped and filtered updates (like with `distinctUntilChanged`):\n\n```swift\n$appState.observe(\\.screens.loginScreen, with: self) { (obj, state) in\n    ...\n}\n```\n\nPro Tip: `\\.self` is also a valid `KeyPath`. This way you can discard the same values while observing a primitive type.\n\n### Installation\n\n@ Carthage\n\n```\ngithub \"nalexn/minimalist\"\n```\n\n@ CocoaPods\n\n```\npod 'Minimalist'\n```\n\n@ SPM\n\n```\n.package(url: \"https://github.com/nalexn/minimalist.git\", from: \"1.0.0\")\n```\n\n---\n\n[![blog](https://img.shields.io/badge/blog-github-blue)](https://nalexn.github.io/?utm_source=nalexn_github) [![venmo](https://img.shields.io/badge/%F0%9F%8D%BA-Venmo-brightgreen)](https://venmo.com/nallexn)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnalexn%2Fminimalist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnalexn%2Fminimalist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnalexn%2Fminimalist/lists"}