Reactjs – Material UI – Open LeftNav / Drawer on AppBar click

material-uireactjs

I'm discovering ReactJS and material-ui (http://material-ui.com/).

I try to create a default template for my application.
I want to use an AppBar and a LeftNav (renamed in Drawer in new versions) in separated components.

The AppBar has a menu button on it by default. I want to use it to open the LeftNav but I don't know how I can call my LeftBarComponent component function to open it.

I've almost understood how to communicate between components but in my case, I don't know how I could do because there is no documentation about it.
The only thing I know to open the LeftNav element is to use LeftNav.toggle()

http://material-ui.com/#/components/left-nav

Thanks for your help.

Default.jsx

use strict';

var React = require('react');
var pageStore = require('../../stores/page');

var MainNavbar = require('../modules/navbar.jsx');
var LeftNavbar = require('../modules/leftbar.jsx');

var getState = function() {
  return {
    title: pageStore.get().title
  };
};

var DefaultComponent = React.createClass({
  mixins: [pageStore.mixin],
  componentDidMount: function() {
    pageStore.emitChange();
  },
  getInitialState: function() {
    return getState();
  },
  render: function() {
    return (
      /* jshint ignore:start */
      <div className="main-container">
        <MainNavbar />
        <LeftNavbar />
        <div className="content">
          {this.props.children}
        </div>
      </div>
      /* jshint ignore:end */
    );
  },
  // Event handler for 'change' events coming from store mixins.
  _onChange: function() {
    this.setState(getState());
  }
});

module.exports = DefaultComponent;

navbar.jsx

'use strict';

var React = require('react');
var routeActions = require('../../actions/routes');

var MUI = require('material-ui');
var AppBar = MUI.AppBar;

// Navbar Component
// Application main menu
// Usage: <Navbar />
var NavbarComponent = React.createClass({
  render: function() {
    return (
      /* jshint ignore:start */
      <AppBar title="MyApp" onMenuIconButtonTouchTap={ this._handleClick }>
        <div className="clear"></div>
      </AppBar>
      /* jshint ignore:end */
    );
  },
  _handleClick: function()
  {
    console.log('ok');
  }
});

module.exports = NavbarComponent;

leftbar.jsx

'use strict';

var React = require('react');
var routeActions = require('../../actions/routes');

var MUI = require('material-ui');
var LeftNav = MUI.LeftNav;
var MenuItem = MUI.MenuItem;

var menuItems = [
  { route: 'home', text: 'Home' },
  { route: 'about', text: 'About' },
];

// LeftBar Component
// Application left menu
// Usage: <LeftBar />
var LeftBarComponent = React.createClass({
  render: function() {
    return (
      /* jshint ignore:start */
      <LeftNav menuItems={menuItems} docked={false} />
      /* jshint ignore:end */
    );
  },
  _handleClick: function()
  {
    console.log('ok');
  }
});

module.exports = LeftBarComponent;

Best Answer

In this case you need to pass the event upwards through your components, and then down again.

    <MainNavbar onClickMenu=this.onClickMenu/>
    <LeftNavbar isOpen=this.state.leftNavIsOpen/>

However, using this in conjunction with Reactjs is not optimal, as the LeftNav material component does not react to attributes, but to method calls like you were saying.

To work around, you could put a check in the LeftNav render method, that checks the current state, and calls toggle() if needed. In principle this goes against the React way of thinking, as a state is contained inside the specific child component and not in the DefaultComponent that handles it.

render:function(){
  if(this.props.isOpen){
     LeftNav.open();
  }
  return ...