{"id":13908029,"url":"https://github.com/ReSwift/ReSwift-Router","last_synced_at":"2025-07-18T06:32:24.105Z","repository":{"id":48825663,"uuid":"48029831","full_name":"ReSwift/ReSwift-Router","owner":"ReSwift","description":"Declarative Routing in Swift, Extension for ReSwift","archived":false,"fork":false,"pushed_at":"2021-07-09T17:37:55.000Z","size":3532,"stargazers_count":496,"open_issues_count":19,"forks_count":81,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-11-20T00:39:04.272Z","etag":null,"topics":[],"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/ReSwift.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-15T08:31:30.000Z","updated_at":"2024-07-07T08:29:48.000Z","dependencies_parsed_at":"2022-09-23T22:24:25.624Z","dependency_job_id":null,"html_url":"https://github.com/ReSwift/ReSwift-Router","commit_stats":null,"previous_names":["swift-flow/swift-flow-router"],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReSwift%2FReSwift-Router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReSwift%2FReSwift-Router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReSwift%2FReSwift-Router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReSwift%2FReSwift-Router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ReSwift","download_url":"https://codeload.github.com/ReSwift/ReSwift-Router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226361635,"owners_count":17612933,"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":[],"created_at":"2024-08-06T23:02:25.328Z","updated_at":"2024-11-25T16:31:20.844Z","avatar_url":"https://github.com/ReSwift.png","language":"Swift","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) \n[![](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Swift-Flow/Swift-Flow/blob/master/LICENSE.md)\n![Platform support](https://img.shields.io/badge/platform-ios%20%7C%20osx%20%7C%20tvos%20%7C%20watchos-lightgrey.svg?style=flat-square)\n\n\nA declarative router for [ReSwift](https://github.com/ReSwift/ReSwift). Allows developers to declare routes in a similar manner as URLs are used on the web.\n\nUsing ReSwiftRouter you can navigate your app by defining the target location in the form of a URL-like sequence of identifiers:\n\n```swift\nmainStore.dispatch(\n    SetRouteAction([\"TabBarViewController\", StatsViewController.identifier])\n)\n```\n\n# About ReSwiftRouter\n\n**ReSwiftRouter is still under development and the API is neither complete nor stable at this point.**\n\nWhen building apps with ReSwift you should aim to cause **all** state changes through actions - this includes changes to the navigation state.\n\nThis requires to store the current navigation state within the app state and to use actions to trigger changes to that state - both is provided ReSwiftRouter.\n\n# Installation\n\n\n## CocoaPods\n\nYou can install ReSwiftRouter via CocoaPods by adding it to your `Podfile`:\n\n\tuse_frameworks!\n\n\tsource 'https://github.com/CocoaPods/Specs.git'\n\tplatform :ios, '8.0'\n\t\n\tpod 'ReSwift'\n\tpod 'ReSwiftRouter'\n\nAnd run `pod install`.\n\n## Carthage\n\nYou can install ReSwiftRouter via [Carthage]() by adding the following line to your Cartfile:\n\n\tgithub \"ReSwift/ReSwift-Router\"\n\n# Configuration\n\nExtend your app state to include the navigation state:\n\n```swift\nimport ReSwiftRouter\n\nstruct AppState: StateType {\n    // other application state\n    var navigationState: NavigationState\n}\n```\n\nAfter you've initialized your store, create an instance of `Router`, passing in a reference to the store and to the root `Routable`. Additionally you will need to provide a closure that describes how to access the `navigationState` of your application state:\n\n```swift\nrouter = Router(store: mainStore, rootRoutable: RootRoutable(routable: rootViewController)) { state in \n\tstate.select { $0.navigationState }\n}\n```\n\nWe'll discuss `Routable` in the next main section.\n\n## Calling the Navigation Reducer\n\nThe `NavigationReducer` is provided as part of `ReSwiftRouter`. You need to call it from within your top-level reducer. Here's a simple example from the specs:\n\n```swift\nstruct AppReducer: Reducer {\n    func handleAction(action: Action, state: FakeAppState?) -\u003e FakeAppState {\n        return FakeAppState(\n            navigationState: NavigationReducer.handleAction(action, state: state?.navigationState)\n        )\n    }\n}\n```\nThis will make reducer handle all routing relevant actions.\n\n# Implementing `Routable`\n\nReSwiftRouter works with routes that are defined, similar to URLs, as a sequence of elements e.g. `[\"Home\", \"User\", \"UserDetail\"]`. \n\nReSwiftRouter is agnostic of the UI framework you are using - it uses `Routable`s to implement that interaction.\n\nEach route element is mapped to one responsible `Routable`. The `Routable` needs to be able to present a child, hide a child or replace a child with another child.\n\nHere is the `Routable` protocol with the methods you should implement:\n\n```swift\n\npublic protocol Routable {\n\n    func push(\n        _ element: RouteElement,\n        animated: Bool,\n        completion: @escaping RoutingCompletion) -\u003e Routable\n\n    func pop(\n        _ element: RouteElement,\n        animated: Bool,\n        completion: @escaping RoutingCompletion)\n\n    func change(\n        _ from: RouteElement,\n        to: RouteElement,\n        animated: Bool,\n        completion: @escaping RoutingCompletion) -\u003e Routable\n\n}\n\n```\n\nAs part of initializing `Router` you need to pass the first `Routable` as an argument. That root `Routable` will be responsible for the first route element.\n\nIf e.g. you set the route of your application to `[\"Home\"]`, your root `Routable` will be asked to present the view that corresponds to the element `\"Home\"`. \n\nWhen working on iOS with UIKit this would mean the `Routable` would need to set the `rootViewController` of the application.  \n\nWhenever a `Routable` presents a new route element, it needs to return a new `Routable` that will be responsible for managing the presented element. If you want to navigate from `[\"Home\"]` to `[\"Home\", \"Users\"]` the `Routable` responsible for the `\"Home\"` element will be asked to present the `\"User\"` element.\n\nIf your navigation stack uses a modal presentation for this transition, the implementation of `Routable` for the `\"Home\"` element might look like this:\n\n```swift\nfunc push(_ element: RouteElement, animated: Bool, completion: @escaping RoutingCompletion) -\u003e Routable {\n\n\tif element == \"User\" {\n\t\t// 1.) Perform the transition\n        userViewController = UIStoryboard(name: \"Main\", bundle: nil)\n            .instantiateViewControllerWithIdentifier(\"UserViewController\") as! Routable\n\n\t\t// 2.) Call the `completion` once the transition is complete\n        presentViewController(userViewController, animated: false,\n            completion: completion)\n\n\t\t// 3.) Return the Routable for the presented element. For convenience\n\t\t// this will often be the UIViewController itself. \n        return userViewController\n   \t}\n   \t\n   \t// ...\n}\n\nfunc pop(_ element: RouteElement, animated: Bool, completion: @escaping RoutingCompletion)\n\n\tif element == \"Home\" {\n    \tdismissViewControllerAnimated(false, completion: completion)\n    }\n    \n    // ...\n}\n```\n\n## Calling the Completion Handler within Routables\n\nReSwiftRouter needs to throttle the navigation actions, since many UI frameworks including UIKit don't allow to perform multiple navigation steps in parallel. Therefor every method of `Routable` receives a `completion` handler. The router will not perform any further navigation actions until the completion handler is called.\n\n# Changing the Current Route\n\nCurrently the only way to change the current application route is by using the `SetRouteAction` and providing an absolute route. Here's a brief example:\n\n```swift\n@IBAction func cancelButtonTapped(sender: UIButton) {\n    mainStore.dispatch(\n        SetRouteAction([\"TabBarViewController\", StatsViewController.identifier])\n    )\n}\n```\nAs development continues, support for changing individual route elements will be added.\n\n\n# Contributing\n\n## Compiling \u0026 Running tests\n\nReSwiftRouter uses [Carthage]() for its development dependencies. To build or test any of the targets, run `carthage bootstrap`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FReSwift%2FReSwift-Router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FReSwift%2FReSwift-Router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FReSwift%2FReSwift-Router/lists"}