Author avatar

Gaurav Singhal

How to Use Backbone Router and React States

Gaurav Singhal

  • Apr 11, 2020
  • 8 Min read
  • 713 Views
  • Apr 11, 2020
  • 8 Min read
  • 713 Views
Web Development
Front End Web Development
Client-side Framework
React

Introduction

BackboneJS is primarily a JavaScript MVC framework, whereas React identifies itself as a JavaScript UI library. BackboneJS provides organized structure to your codebase and definitive models that can communicate with data. Using React as a view library in BackboneJS will improve your application's performance as React uses the virtual DOM.

In this guide, you'll learn how to use React components with a Backbone router.

Problems with the Existing View in BackboneJS

Backbone view is the template model that takes care of the UI and layout. A backbone view is identical to a React components in terms of function, but the working and performance differs. There are some problems you should be aware of when it comes to using Backbone views. This guide won't solve these issues, but will offer an alternate method using React components.

Non-reusable Views

Backbone views are much more challenging to reuse than React components. They sometimes become unhelpful and usually rely on rendering engines like Underscore or Mustache, which may restrict functionality.

Updating the DOM Is Tough

A typical pattern in BackboneJS is to listen to a variety of DOM events (click, change, etc.) and when triggered, manually refresh the DOM using jQuery to remove and append different elements.

Performance Problems

When it comes to performance, Backbone views cannot update DOM parts without re-rendering the whole DOM, which can be very costly. React overcomes this problem by using the virtual DOM and only updating the DOM parts that need a re-render.

Backbone Router

Backbone routers are used for routing your web application's URLs. Earlier, hash fragments (#page) were used to route the URLs, but with the introduction of the History API, it is now possible to route with standard URLs (/page).

Backbone routers don't exactly fit the traditional definition of an MVC router, although a Backbone router is still handy for any application that needs URL routing abilities. In a traditional MVC framework, the routing happens on the server side, whereas in Backbone the routing is handled in the client side by the browser.

Specified routers should always contain at least one route and a function to map the particular route to its corresponding view. In the example below, you can see how the routes are defined using Backbone.Router.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Backbone from "backbone";

const Router = Backbone.Router.extend({
  routes: {
    foo: "foo",
    bar: "bar"
  },
  foo: function () {
    // action to map foo URL to the specific view
  },
  bar: function () {
    // action to map bar URL to the specific view
  }
});

new Router();
js

The extend() method creates a custom route class. It defines action functions that are triggered when certain URL parts are matched and provide a routes hash that pairs routes to specific actions.

The routes object defines a key-value pair for the router, where the key is the URL fragment and the value is its route or action function.

You can also pass route params into your route action by defining a parameter part such as :param, which matches a single URL component between slashes. It can be made optional by wrapping it in parenthesis: (/:param).

1
2
3
4
5
6
7
8
const Router = Backbone.Router.extend({
  routes: {
    "foo/:id": "foo"
  },
  foo: function (id) {
    console.log("Route param : ", id);
  }
});
js

Once the router has been instantiated and all of the routes are set up properly, call Backbone.history.start() to begin watching URL change or hashchange events and dispatching route actions. To use a regular URL structure instead of hash URLs, you can pass the pushState option to the start() method Backbone.history.start({ pushState: true }).

Rendering React Component Inside Route Action

In this section, you'll learn how to render a React component from within the route action function.

Start fresh by defining a new Router class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Router, history } from "backbone";

const AppRouter = Router.extend({
  routes: {
    "": "init",
    "profile/:id": "profile",
    "search/:term": "search"
  },
  init: () => {
    console.log("This is the first page");
  },
  profile: id => {
    console.log("This is the profile page", id);
  },
  search: term => {
    console.log("The user is searching for " + term);
  }
});

new AppRouter();

history.start({ pushState: true });
js

If you see the console logs when you navigate to the URLs, that means the routing has been set up perfectly.

Next, create React components for each route action.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from "react";

const IndexPage = () => (
  <div>
    <h1>Hey, this is the Home Page.</h1>
  </div>
);

const ProfilePage = props => (
  <div>
    <h1>Thanks for visiting the Profile Page</h1>
    <h2>The Profile ID is {props.profileId}</h2>
  </div>
);

const SearchPage = props => (
  <div>
    <h1>Searching for {props.searchTerm}...</h1>
  </div>
);
jsx

To render the component in a DOM element, use the ReactDOM.render() method, just as you would in any other React application. To try it out, render the <IndexPage /> component from the init() function.

1
2
3
4
5
6
7
8
9
10
11
import ReactDOM from "react-dom";

const rootElement = document.getElementById("root");

routes: {
  // ...
}
init: () => {
  ReactDOM.render(<IndexPage />, rootElement);
};
//
jsx

Now, if you visit the index URL, you should see the contents of the <IndexPage /> component. Instead of calling ReactDOM.render() again and again, create a helper function to render a component.

Put it all together and pass on the route parameters as props to the respective page components.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...
const rootElement = document.getElementById("root");

const renderView = View => ReactDOM.render(View, rootElement);

const AppRouter = Router.extend({
  routes: {
    "": "init",
    "profile/:id": "profile",
    "search/:term": "search"
  },
  init: () => renderView(<IndexPage />),
  profile: id => renderView(<ProfilePage profileId={id} />),
  search: term => renderView(<SearchPage searchTerm={term} />)
});

// ...
jsx

Complete Source Code

Below you can find the complete code for your reference.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React from "react";
import ReactDOM from "react-dom";
import { Router, history } from "backbone";

const rootElement = document.getElementById("root");

const renderView = View => ReactDOM.render(View, rootElement);

const IndexPage = () => (
  <div>
    <h1>Hey, this is the Home Page.</h1>
  </div>
);

const ProfilePage = props => (
  <div>
    <h1>Thanks for visiting the Profile Page</h1>
    <h2>The Profile ID is {props.profileId}</h2>
  </div>
);

const SearchPage = props => (
  <div>
    <h1>Searching for {props.searchTerm}...</h1>
  </div>
);

const AppRouter = Router.extend({
  routes: {
    "": "init",
    "profile/:id": "profile",
    "search/:term": "search"
  },
  init: () => renderView(<IndexPage />),
  profile: id => renderView(<ProfilePage profileId={id} />),
  search: term => renderView(<SearchPage searchTerm={term} />)
});

new AppRouter();

history.start({ pushState: true });
jsx

Conclusion

Backbone routes are simply objects that can handle the incoming route value from the URL and invoke a specific action for that route.

An important takeaway from this guide is that you should be flexible in implementing two or more JavaScript stacks into your application codebase. Doing so will help you get a general idea of how different libraries work with each other and how you can overcome each of their disadvantages.

2