- Notifications
You must be signed in to change notification settings - Fork79
Declarative Routing in Swift, Extension for ReSwift
License
ReSwift/ReSwift-Router
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A declarative router forReSwift. Allows developers to declare routes in a similar manner as URLs are used on the web.
Using ReSwiftRouter you can navigate your app by defining the target location in the form of a URL-like sequence of identifiers:
mainStore.dispatch(SetRouteAction(["TabBarViewController",StatsViewController.identifier]))
ReSwiftRouter is still under development and the API is neither complete nor stable at this point.
When building apps with ReSwift you should aim to causeall state changes through actions - this includes changes to the navigation state.
This 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.
You can install ReSwiftRouter via CocoaPods by adding it to yourPodfile:
use_frameworks!source 'https://github.com/CocoaPods/Specs.git'platform :ios, '8.0'pod 'ReSwift'pod 'ReSwiftRouter'And runpod install.
You can install ReSwiftRouter viaCarthage by adding the following line to your Cartfile:
github "ReSwift/ReSwift-Router"Extend your app state to include the navigation state:
import ReSwiftRouterstructAppState:StateType{ // other application statevarnavigationState:NavigationState}
After you've initialized your store, create an instance ofRouter, passing in a reference to the store and to the rootRoutable. Additionally you will need to provide a closure that describes how to access thenavigationState of your application state:
router=Router(store: mainStore, rootRoutable:RootRoutable(routable: rootViewController)){ statein state.select{ $0.navigationState}}
We'll discussRoutable in the next main section.
TheNavigationReducer is provided as part ofReSwiftRouter. You need to call it from within your top-level reducer. Here's a simple example from the specs:
structAppReducer:Reducer{func handleAction(action:Action, state:FakeAppState?)->FakeAppState{returnFakeAppState( navigationState:NavigationReducer.handleAction(action, state: state?.navigationState))}}
This will make reducer handle all routing relevant actions.
ReSwiftRouter works with routes that are defined, similar to URLs, as a sequence of elements e.g.["Home", "User", "UserDetail"].
ReSwiftRouter is agnostic of the UI framework you are using - it usesRoutables to implement that interaction.
Each route element is mapped to one responsibleRoutable. TheRoutable needs to be able to present a child, hide a child or replace a child with another child.
Here is theRoutable protocol with the methods you should implement:
publicprotocolRoutable{func push( _ element:RouteElement, animated:Bool, completion:@escapingRoutingCompletion)->Routablefunc pop( _ element:RouteElement, animated:Bool, completion:@escapingRoutingCompletion)func change( _ from:RouteElement, to:RouteElement, animated:Bool, completion:@escapingRoutingCompletion)->Routable}
As part of initializingRouter you need to pass the firstRoutable as an argument. That rootRoutable will be responsible for the first route element.
If e.g. you set the route of your application to["Home"], your rootRoutable will be asked to present the view that corresponds to the element"Home".
When working on iOS with UIKit this would mean theRoutable would need to set therootViewController of the application.
Whenever aRoutable presents a new route element, it needs to return a newRoutable that will be responsible for managing the presented element. If you want to navigate from["Home"] to["Home", "Users"] theRoutable responsible for the"Home" element will be asked to present the"User" element.
If your navigation stack uses a modal presentation for this transition, the implementation ofRoutable for the"Home" element might look like this:
func push(_ element:RouteElement, animated:Bool, completion:@escapingRoutingCompletion)->Routable{if element=="User"{// 1.) Perform the transition userViewController=UIStoryboard(name:"Main", bundle:nil).instantiateViewControllerWithIdentifier("UserViewController")as!Routable// 2.) Call the `completion` once the transition is completepresentViewController(userViewController, animated:false, completion: completion)// 3.) Return the Routable for the presented element. For convenience// this will often be the UIViewController itself.return userViewController} // ...}func pop(_ element:RouteElement, animated:Bool, completion:@escapingRoutingCompletion)if element=="Home"{dismissViewControllerAnimated(false, completion: completion)} // ...}
ReSwiftRouter 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 ofRoutable receives acompletion handler. The router will not perform any further navigation actions until the completion handler is called.
Currently the only way to change the current application route is by using theSetRouteAction and providing an absolute route. Here's a brief example:
@IBActionfunc cancelButtonTapped(sender:UIButton){ mainStore.dispatch(SetRouteAction(["TabBarViewController",StatsViewController.identifier]))}
As development continues, support for changing individual route elements will be added.
ReSwiftRouter usesCarthage for its development dependencies. To build or test any of the targets, runcarthage bootstrap.
About
Declarative Routing in Swift, Extension for ReSwift
Resources
License
Uh oh!
There was an error while loading.Please reload this page.