Giter Club home page Giter Club logo

reswift-router's Introduction

Carthage compatible Platform support

A declarative router for ReSwift. 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])
)

#About ReSwiftRouter

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 cause all 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.

#Installation

##Cocoapods

You can install ReSwiftRouter via CocoaPods by adding it to your Podfile:

use_frameworks!

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

pod 'ReSwift'
pod 'ReSwiftRouter'

And run pod install.

##Carthage

You can install ReSwiftRouter via Carthage by adding the following line to your Cartfile:

github "ReSwift/ReSwiftRouter"

#Configuration

Extend your app state to include the navigation state by conforming to the HasNavigationState protocol and adding the a navigationState member as follows:

import ReSwiftRouter

struct AppState: StateType, HasNavigationState {
    // other application state
    var navigationState = NavigationState()
}

After you've initialized your store, create an instance of Router, passing in a reference to the store and to the root Routable:

router = Router(store: mainStore, rootRoutable: RootRoutable(routable: rootViewController))

We'll discuss Routable in the next main section.

##Calling the Navigation Reducer

The 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:

struct AppReducer: Reducer {
    func handleAction(action: Action, state: FakeAppState?) -> FakeAppState {
        return FakeAppState(
            navigationState: NavigationReducer.handleAction(action, state: state?.navigationState)
        )
    }
}

This will reducer will handle all routing relevant actions.

#Implementing Routable

ReSwiftRouter works with routes that are defined, similar to URLs, as a sequence of identifiers e.g. ["Home", "User", "UserDetail"].

ReSwiftRouter is agnostic of the UI framework you are using - it uses Routables to implement that interaction.

Each route segment 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.

Here is the Routable protocol with the methods you should implement:

protocol Routable {

    func changeRouteSegment(from: RouteElementIdentifier,
        to: RouteElementIdentifier,
        completionHandler: RoutingCompletionHandler) -> Routable

    func pushRouteSegment(routeElementIdentifier: RouteElementIdentifier,
        completionHandler: RoutingCompletionHandler) -> Routable

    func popRouteSegment(routeElementIdentifier: RouteElementIdentifier,
        completionHandler: RoutingCompletionHandler)

}

As part of initializing Router you need to pass the first Routable as an argument. That root Routable will be responsible for the first route segment.

If 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 identifier "Home".

When working on iOS with UIKit this would mean the Routable would need to set the rootViewController of the application.

Whenever a Routable presents a new route segment, it needs to return a new Routable that will be responsible for managing the presented segment. If you want to navigate from ["Home"] to ["Home", "Users"] the Routable responsible for the "Home" segment will be asked to present the "User" segment.

If your navigation stack uses a modal presentation for this transition, the implementation of Routable for the "Home" segment might look like this:

func pushRouteSegment(identifier: RouteElementIdentifier,
    completionHandler: RoutingCompletionHandler) -> Routable {
    
	if identifier == "Home" {
		// 1.) Perform the transition
        userViewController = UIStoryboard(name: "Main", bundle: nil)
            .instantiateViewControllerWithIdentifier("UserViewController") as! Routable

		// 2.) Call the `completionHandler` once the transition is complete
        presentViewController(userViewController, animated: false,
            completion: completionHandler)

		// 3.) Return the Routable for the presented segment. For convenience
		// this will often be the UIViewController itself. 
        return userViewController
   	}
   	
   	// ...
}

func popRouteSegment(identifier: RouteElementIdentifier,
    completionHandler: RoutingCompletionHandler) {

	if identifier == "Home" {
    	dismissViewControllerAnimated(false, completion: completionHandler)
    }
    
    // ...
}

##Calling the Completion Handler within Routables

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 of Routable receives a completionHandler. The router will not perform any further navigation actions until the completion handler is called.

#Changing the Current Route

Currently the only way to change the current application route is by using the SetRouteAction and providing an absolute route. Here's a brief example:

@IBAction func cancelButtonTapped(sender: UIButton) {
    mainStore.dispatch(
        SetRouteAction(["TabBarViewController", StatsViewController.identifier])
    )
}

As development continues, support for changing individual route segments will be added.

reswift-router's People

Contributors

ben-g avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.