{"id":2143,"date":"2015-06-23T13:02:52","date_gmt":"2015-06-23T07:32:52","guid":{"rendered":"http:\/\/codetheory.in\/?p=2143"},"modified":"2015-09-04T13:12:47","modified_gmt":"2015-09-04T07:42:47","slug":"react-integrating-routing-to-material-uis-left-nav-or-other-components","status":"publish","type":"post","link":"https:\/\/codetheory.in\/react-integrating-routing-to-material-uis-left-nav-or-other-components\/","title":{"rendered":"React Integrating Routing to Material UI’s Left Nav (or Other Components)"},"content":{"rendered":"

Working with the React Material UI and trying to make routing work (or even understand how it works) with clicks on the LeftNav<\/a> item items ? It’s actually quite simple once you get a hang of it. I’ll show you the code and explain the logic behind how on clicking navigation links in LeftNav you navigate to different pages\/URLs in your app\/website (in a snap). We’ll be using React Router<\/a>, Material UI<\/a> and obviously, ReactJS<\/a> itself. I’ve also uploaded the code to Github<\/a>.<\/p>\n

<\/p>\n

Setup<\/h2>\n

Let’s first quickly setup the LeftNav<\/a> and integrate it with the AppBar<\/a>. The approach that we’ll take is, code our app with components in Node and finally create a bundle.js<\/code> for the browser using the famous browserify<\/a>. Oh and also we’ll be coding in ES6! Let’s kick off with our index.js<\/code>:<\/p>\n

\r\nimport React from 'react';\r\nimport mui from 'material-ui';\r\nimport injectTapEventPlugin from 'react-tap-event-plugin';\r\nimport Router, { Route, DefaultRoute, NotFoundRoute, Redirect, Link } from 'react-router';\r\n\r\ninjectTapEventPlugin();\r\n\r\nimport App from '.\/components\/App';\r\nimport Home from '.\/components\/Home';\r\nimport About from '.\/components\/About';\r\nimport Contact from '.\/components\/Contact';\r\n\r\nconst AppRoutes = (\r\n  <Route path="\/" handler={App}>\r\n    <DefaultRoute handler={Home} \/>\r\n    <Route name="about" handler={About} \/>\r\n    <Route name="contact" handler={Contact} \/>\r\n  <\/Route>\r\n);\r\n\r\nRouter.run(AppRoutes, Router.HashLocation, (Root) => {\r\n  React.render(<Root \/>, document.body);\r\n});\r\n<\/pre>\n

So we import our plugins, then our components too and we initialize the react-tap-event-plugin<\/a> too. Finally we define our routes and their component handlers which is finally run to render our all. If you don’t understand the routing piece, feel free to refer to the docs<\/a> or just copy paste code for now :-).<\/p>\n

Now let’s define our components one by one.<\/p>\n

\r\n\/\/ components\/Home.js\r\nimport React from 'react';\r\n\r\nclass Home extends React.Component {\r\n  render() {\r\n    return (\r\n      <h2>Home<\/h2>\r\n    );\r\n  }\r\n}\r\n\r\nexport default Home;\r\n<\/pre>\n
\r\n\/\/ components\/About.js\r\n\r\nimport React from 'react';\r\n\r\nclass About extends React.Component {\r\n  render() {\r\n    return (\r\n      <h2>About<\/h2>\r\n    );\r\n  }\r\n}\r\n\r\nexport default About;\r\n<\/pre>\n
\r\n\/\/ components\/Contact.js\r\n\r\nimport React from 'react';\r\n\r\nclass Contact extends React.Component {\r\n  render() {\r\n    return (\r\n      <h2>Contact<\/h2>\r\n    );\r\n  }\r\n}\r\n\r\nexport default Contact;\r\n<\/pre>\n

All they do is render a heading. Finally here’s the main big piece which renders the entire app (also set as the parent Route handler in our routes configuration):<\/p>\n

\r\n\/\/ components\/App.js\r\n\r\nimport React from 'react';\r\nimport mui from 'material-ui';\r\nimport { RouteHandler } from 'react-router';\r\n\r\n\/\/ Get mui Components\r\nlet ThemeManager = new mui.Styles.ThemeManager();\r\nlet AppBar = mui.AppBar\r\n  , LeftNav = mui.LeftNav\r\n  , MenuItem = mui.MenuItem;\r\n\r\n\/\/ Define menu items for LeftNav\r\nlet menuItems = [\r\n  { route: '\/', text: 'Home' },\r\n  { route: 'about', text: 'About' },\r\n  { route: 'contact', text: 'Contact' },\r\n];\r\n\r\nclass App extends React.Component {\r\n\r\n  constructor() {\r\n    super();\r\n\r\n    this._handleClick = this._handleClick.bind(this);\r\n    this._getSelectedIndex = this._getSelectedIndex.bind(this);\r\n    this._onLeftNavChange = this._onLeftNavChange.bind(this);\r\n  }\r\n\r\n  getChildContext() {\r\n    return {\r\n      muiTheme: ThemeManager.getCurrentTheme()\r\n    };\r\n  }\r\n\r\n  _handleClick(e) {\r\n    e.preventDefault();\r\n\r\n    this.refs.leftNav.toggle();\r\n  }\r\n\r\n  \/\/ Get the selected item in LeftMenu\r\n  _getSelectedIndex() {\r\n    let currentItem;\r\n\r\n    for (let i = menuItems.length - 1; i >= 0; i--) {\r\n      currentItem = menuItems[i];\r\n      if (currentItem.route && this.context.router.isActive(currentItem.route)) {\r\n        return i;\r\n      }\r\n    }\r\n  }\r\n\r\n  _onLeftNavChange(e, key, payload) {\r\n    \/\/ Do DOM Diff refresh\r\n    this.context.router.transitionTo(payload.route);\r\n  }\r\n\r\n  render() {\r\n\r\n    return (\r\n      <div id="page_container">\r\n\r\n        <LeftNav\r\n          ref="leftNav"\r\n          docked={false}\r\n          menuItems={menuItems}\r\n          selectedIndex={this._getSelectedIndex()}\r\n          onChange={this._onLeftNavChange} \/>\r\n\r\n        <header>\r\n          <AppBar title='MUI Routing' onLeftIconButtonTouchTap={this._handleClick} \/>\r\n        <\/header>\r\n\r\n        <section className="content">\r\n          <RouteHandler \/>\r\n        <\/section>\r\n\r\n      <\/div>\r\n    );\r\n  }\r\n\r\n}\r\n\r\nApp.childContextTypes = {\r\n  muiTheme: React.PropTypes.object\r\n};\r\n\r\nApp.contextTypes = {\r\n  router: React.PropTypes.func\r\n};\r\n\r\nmodule.exports = App;\r\n<\/pre>\n

We render the LeftNav, AppBar and the RouteHandler (most important component to switch among Home, About and Contact). Toggling the LeftNav from the header (AppBar) is handled by our custom _handleClick()<\/code> method which is fired on the onLeftIconButtonTouchTap<\/code> event. That was simple, but the routing logic will require some explanation.<\/p>\n

Routing Logic<\/h2>\n

So the first thing to notice is the onChange<\/code> event of the LeftNav for which we’ve specified the _onLeftNavChange()<\/code> handler. That gets called whenever a menu item is clicked which is not the currently selected one. What that handler does is, calls the transitionTo()<\/code><\/a> method on the Router object with the menu item’s route<\/code> value (passed as payload<\/code> in the code). Once the URL changes, the callback we passed to Router.run()<\/code> is fired again which does a re-rendering (virtual dom diff rendering and jazz) that shows the selected component immediately. The _getSelectedIndex()<\/code> is used to fetch the menu’s selected item’s index so that it can be styled differently (active state) in the UI.<\/p>\n

You might be wondering where does the this.context.router<\/code> comes from. Notice we pass that to App.contextTypes<\/code> to access that property passed down from the parent. If you don’t know what context types are, then read this article<\/a>.<\/p>\n

This logic was taken from material ui’s documentation source<\/a>.<\/p>\n

Now that you know how the LeftNav menu items can be integrated with react-router, it should be super simple to do the same with other components of material UI like a button or a tab. All you’ve to do is find the click\/active\/change\/etc. events, access `router` by specifying it in the contextTypes<\/code> and call the transitionTo()<\/code> method on the Router. The tabs component even has an example<\/a>.<\/p>\n

Cheers!<\/p>\n","protected":false},"excerpt":{"rendered":"

Working with the React Material UI and trying to make routing work (or even understand how it works) with clicks on the LeftNav item items ? It’s actually quite simple once you get a hang of it. I’ll show you the code and explain the logic behind how on clicking navigation links in LeftNav you … Continue reading “React Integrating Routing to Material UI’s Left Nav (or Other Components)”<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40,12],"tags":[8,153],"_links":{"self":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts\/2143"}],"collection":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/comments?post=2143"}],"version-history":[{"count":4,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts\/2143\/revisions"}],"predecessor-version":[{"id":2166,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/posts\/2143\/revisions\/2166"}],"wp:attachment":[{"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/media?parent=2143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/categories?post=2143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codetheory.in\/wp-json\/wp\/v2\/tags?post=2143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}