18

I'm new to React native (and React) and I'm playing around a little bit with it.

I managed to add a DrawerLayout that I can drag from the left of my screen. However I'd like to open it when I click on my menu icon in my ToolbarAndroid.

I tried to use "refs" but it doesn't seem to work

I hope I'm clear enough.

Thank you

Maslow
  • 1,084
  • 9
  • 22

5 Answers5

32

You should use "refs" as you've mentioned. To do so, for your drawer component have "ref" attribute set:

<DrawerLayoutAndroid
   ...
   ref={'DRAWER_REF'}
   ...
/>

Then in your component use this.refs to access it and call openDrawer or closeDrawer on that ref (e.g. you may want to have Touchable element that will trigger this call):

this.refs['DRAWER_REF'].openDrawer();
kzzzf
  • 2,614
  • 1
  • 16
  • 7
  • It doesn't seem to work, but I guess it's because I don't have access to this.refs on this component. My components are nested this way DrawerLayoutAndroid > Navigator (which render a scene) including a ToolbarAndroid in which I'm trying to to onIconClicked={this.refs['DRAWER_REF'].openDrawer()} – Maslow Sep 22 '15 at 05:35
  • 2
    `this.refs['DRAWER_REF']` will only be accessible from the component that renders the drawer. If you want to access it from some component down the view hierarchy you need to either: pass ref down the view hierarchy as a property OR pass a callback method down the view hierarchy that will be defined on drawer parent component level – kzzzf Sep 23 '15 at 07:49
  • 4
    i am getting "undefined is not a object (evaluating 'this.refs['DRAWER_REF']') – John Mar 11 '16 at 12:08
  • can i use many component with `ref` like. ` }>` and inside `` has ` ` . When click icon refs is not ` undefined`. – lwinkyawmyat May 11 '16 at 03:56
  • 1
    I think many of us tried this and got "undefined is not an object" error. Can someone please show us a rather complete code on this? – Fadils May 31 '16 at 04:04
  • Drawer is opening in my emulator smoothly but it doesn't seems to work properly in my mobile device, it takes a while for the drawer to get opened. – Sumit Kushwaha Oct 12 '16 at 13:05
  • I fixed it by adding: onPress={() => this.refs.drawer.openDrawer()} to my button. My drawer simply have: ref="drawer" – Steffen Christensen Oct 13 '16 at 09:29
8

Using the ReactNative sample, you can do like that:

var DrawerTest = React.createClass({
  openDrawer:function() {
    this.refs['DRAWER'].openDrawer()
  },
  render: function() {
    var navigationView = (
        <View style={{flex: 1, backgroundColor: '#fff'}}>
          <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
        </View>
    );
    return (
          <DrawerLayoutAndroid
              drawerWidth={300}
              ref={'DRAWER'}
              drawerPosition={DrawerLayoutAndroid.positions.Left}
              renderNavigationView={() => navigationView}>
            <View style={{flex: 1, alignItems: 'center'}}>
              <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
              <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
              <TouchableHighlight onPress={this.openDrawer}>
                <Text>{'Open Drawer'}</Text>
              </TouchableHighlight>
            </View>
          </DrawerLayoutAndroid>
    );

  }
});

Full File Gist

Tiago Gouvêa
  • 15,036
  • 4
  • 75
  • 81
2

Just want to add another solution, especially when Navigator is used to render the scene.

If this is the case, then the above solutions won't work as it doesn't have access to ref specified in the DrawerLayoutAndroid, and it will in fact return

"undefined is not an object (evaluating 'this.refs['DRAWER_REF']')"

or something like that.

Solution:

Create our own Toolbar so that we can pass our rendering component to it.

MyToolbar.js

... import stuff ...

module.exports = React.createClass({
  render: function() {
    return (
      <ToolbarAndroid
        title={this.props.title}
        navIcon = {{uri: "ic_menu_white_24dp", isStatic: true}}
        style = {styles.toolbar}
        titleColor='#FFFFFF'
        onIconClicked={this._onIconClicked}/>
    );
  },

  _onIconClicked: function(){
    this.props.sidebarRef.refs['DRAWER'].openDrawer();
    // sidebarRef is the rendering component we're passing
  }
});

OpenDrawerFromToolbar.js

...
module.exports = React.createClass({
  render: function() {
    var navigationView = (
      <View style={{flex: 1, backgroundColor: '#fff'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>In the Drawer!</Text>
      </View>
    );

    return (
      <View style={styles.container}>
        <DrawerLayoutAndroid drawerWidth = {300}
                         drawerPosition = {DrawerLayoutAndroid.positions.Left}
                         renderNavigationView = {() => navigationView}
                         ref={'DRAWER'}>
        <MyToolbar style={styles.toolbar}
                   title={'My Awesome App'}
                   navigator={this.props.navigator}
                   sidebarRef={this}/> // pass the component to MyToolbar
        <View style = {{flex: 1, alignItems: 'center'}}>
          <Text style = {{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
          <Text style = {{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
        </View>
      </DrawerLayoutAndroid>
    </View>
  );
  },

  _setDrawer: function() {
    this.refs['DRAWER'].openDrawer();
  }
});

Then our Navigator component with its renderingScene function will work:

module.exports = React.createClass({
  render: function() {
    return (
      <Navigator
        style = {styles.container}
        initialRoute = {{ name: 'openDrawerFromToolbar', index: 0 }}
        renderScene = {this.navigatorRenderScene}
        configureScene={ () => { return Navigator.SceneConfigs.PushFromRight; }}/>
  );
},

navigatorRenderScene: function(route, navigator) {
  _navigator = navigator;
      return (
          <OpenDrawerFromToolbar
            route={route}
            navigator={navigator}
            data={route.data}/>
      );
  }
});
Fadils
  • 1,508
  • 16
  • 21
2

"undefined is not an object" - Most of us ended up here with a above solution.

Please ensure that you have correctly used the ES6 syntax as mentioned below.

Incorrect Syntax:

onPress={this.drawer()}

Correct Syntax:

onPress={() => this.drawer()}

Code:

<DrawerLayoutAndroid
   ...
   ref={'DRAWER_REF'}
   ...
/>

--------------------------------------------------

//Write this just before render() method

drawer = () => {
  this.refs['DRAWER_REF'].openDrawer();
}

--------------------------------------------------

<TouchableHighlight onPress={() => this.drawer()}>
   <Icon name="bars" size={30} color="#900"/>
</TouchableHighlight>
Edison D'souza
  • 4,551
  • 5
  • 28
  • 39
0

Following all those snippets and still getting the undefined is not an object error.

Then found this thread on GitHub which finally solved my issue and explains the refs problem perfectly.

To follow the DrawerLayoutAndroid example on the React Native documentation (http://facebook.github.io/react-native/docs/drawerlayoutandroid.html), this is the code which works:

constructor() {
  super();
  this.openDrawer = this.openDrawer.bind(this);
} 

openDrawer() {
  this.drawer.openDrawer();
}

render() {
  var navigationView = (
    <View style={{flex: 1, backgroundColor: '#fff'}}>
      <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
    </View>
  );
  return (
    <DrawerLayoutAndroid
      drawerWidth={300}
      ref={(_drawer) => this.drawer = _drawer}
      drawerPosition={DrawerLayoutAndroid.positions.Left}
      renderNavigationView={() => navigationView}>
      <View style={{flex: 1, alignItems: 'center'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
        <TouchableHighlight onPress={this.openDrawer}>
          <Text>{'Open Drawer'}</Text>
        </TouchableHighlight>
      </View>
    </DrawerLayoutAndroid>
  );
}
GuGuss
  • 81
  • 7