Hello World

We're going to build an example that'll get you familiar with the Navigation router's data-first approach. The example will have two views. One view will display a Hyperlink that says 'Hello'. Clicking this Hyperlink will navigate you to the second view displaying the text 'World' inside a div. We'll pass across a number that we'll use to set the div's font-size.

To get things started, we'll create a new StateNavigator by passing in an array of States that represent the views in our example. There'll be one State for the 'hello' view and another for the 'world' view. With other routers, you'd have to configure your routes at this stage. With the Navigation router, you can leave your routes until the end. All routes apart from the empty route, that is, which we'll assign to the 'hello' State so that it's active when the page first loads.

var stateNavigator = new Navigation.StateNavigator([
  {key: 'hello', route: ''},
  {key: 'world'}
]);

We define the view for the 'hello' State in a function attached to its renderView property. Inside the function we'll render a Hyperlink that navigates to the 'world' State. We'll let the NavigationLink component handle the rendering. It has a stateKey prop that holds the key of the destination State.

stateNavigator.states.hello.renderView = function() {
  return (
    <NavigationReact.NavigationLink stateKey="world">
      Hello
    </NavigationReact.NavigationLink>
  );
};

We'll also add a renderView function to the 'world' State so we can render the div after the Hyperlink is clicked.

stateNavigator.states.world.renderView = function() {
  return <div>World</div>;
}

To get the example going we'll call start on the stateNavigator. This navigates to the State whose route matches the browser Url. The 'hello' State will be active when the page first loads because we assigned it the empty route.

stateNavigator.start();

We'll set up the Navigation context so that we can render the view for the active State. We'll render a context Consumer component and assign it a child render function. Whenever the active State changes, the Consumer calls our function and we return the matching view.

ReactDOM.render(
  <NavigationReact.NavigationHandler stateNavigator={stateNavigator}>
    <NavigationReact.NavigationContext.Consumer>
      {({ state, data }) => state.renderView(data)}
    </NavigationReact.NavigationContext.Consumer>
  </NavigationReact.NavigationHandler>,
  document.getElementById('app')
);

Data First

We'll change the Hyperlink to pass across a number that will become the font-size of the div. With other routers, we'd have to decide now whether to pass it as a route or query string parameter. With the Navigation router, we can leave this decision to the end. The NavigationLink component has a navigationData prop that holds the data to pass to the destination State. We'll pass the number 20 as the size to the 'world' State.

stateNavigator.states.hello.renderView = function() {
  return (
    <NavigationReact.NavigationLink 
      stateKey="world"
      navigationData={{size: 20}}>
      Hello
    </NavigationReact.NavigationLink>
  );
};

We'll change the 'world' State's renderView function to accept the data as a parameter and use the number passed in to set the div's font-size.

stateNavigator.states.world.renderView = function(data) {
  return (
    <div style={{fontSize: data.size}}>World</div>,
  );
};

Routes Last

Our example's up and running. But, because we haven't set a route for the 'world' State, the Navigation router auto-generates the Url. It turns size into a query string parameter and adds trailing digits to track the type of the size parameter. We'll tidy up the Url by making size a route parameter and defaulting its type to 'number'. The rest of the code remains unchanged because the data we're passing around hasn't changed.

var stateNavigator = new Navigation.StateNavigator([
  {key: 'hello', route: ''},
  {key: 'world', route: '{size}', defaultTypes: {size: 'number'}}
]);

Ta-dah!

With other routers, your Urls are set upfront and changes can ripple throughout your codebase. With the Navigation router, Urls are just a string representation of your typed data. You can safely update routes or switch between query and route parameters without impacting your code.