Alex
Alex

Reputation: 467

React Toggle Menu

Im trying to build an Toggle right menu from this example : how-to-build-a-sliding-menu-using-react-js"

the problem is React.createClass is deprecated so i have to change the code and it stop working i get the content but cant access the handlers cann anybody tell me which steps should i do to fix this issue! so if i click on my button i get this error:

Uncaught TypeError: Cannot read property 'show' of undefined

ToggleMenu

import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import localStyles from './ToggleMenu.scss';
import { themr } from 'react-css-themr';
import { Menu } from '../../components';
import { MenuItem } from '../../components';

@themr('ToggleMenu', localStyles)

export default class ToggleMenu extends React.Component {

  showRight() {
    this.refs.right.show();
  }

  constructor(props) {
    super(props);
    this.showRight = this.showRight.bind(this);
  }

  render() {

    return (
      <div>
      <button onClick={this.showRight}>Show Right Menu!</button>
      <Menu ref={right => this.right = right} alignment="right">
      <MenuItem hash="first-page">First Page</MenuItem>
      <MenuItem hash="second-page">Second Page</MenuItem>
      <MenuItem hash="third-page">Third Page</MenuItem>
      </Menu>
      </div>
    );
  }
}

Menu

import React from 'react';

export default class Menu extends React.Component {
    constructor() {
        super();
        this.state = {
            visible: false
        }
    };

    show() {
        this.setState({visible: true});
        document.addEventListener("click", this.hide.bind(this));
    }

    hide() {
        this.setState({visible: false});
        document.removeEventListener("click", this.hide.bind(this));
    }

    render() {
        return (
            <div className="menu">
                <div className={(this.state.visible ? "visible " : "") + this.props.alignment}>{this.props.children}</div>
            </div>
        );
    }
}

MenuItem

import React from 'react';

export default class MenuItem extends React.Component {
    navigate(hash) {
        window.location.hash = hash;
    }

    render() {
        return (
            <div className="menu-item" onClick={this.navigate.bind(this, this.props.hash)}>{this.props.children}</div>
        );
    }
}

Upvotes: 1

Views: 18092

Answers (1)

Crysfel
Crysfel

Reputation: 8158

The problem is that you are assigning the reference to this.right, you need to update the showRight method to something like this:

showRight() {
  this.right.show();
}

I'd also use an arrow function to avoid binding the function in the constructor.

import React, { PureComponent } from 'react';

export default class ToggleMenu extends PureComponent {

  showRight = () => {
    this.right.show();
  }

  render() {

    return (
      <div>
      <button onClick={this.showRight}>Show Right Menu!</button>
      <Menu ref={right => this.right = right} alignment="right">
      <MenuItem hash="first-page">First Page</MenuItem>
      <MenuItem hash="second-page">Second Page</MenuItem>
      <MenuItem hash="third-page">Third Page</MenuItem>
      </Menu>
      </div>
    );
  }
}

And make sure to use PureComponent to avoid rendering the component when is not needed.

Edit:

The Menu class is not the react way, if you want to hide an element you should do something like the following:

import React from 'react';

export default class Menu extends React.Component {
    state = {
      visible: false,
    };

    show() {
      this.setState({ visible: true });
    }

    hide() {
      this.setState({ visible: false });
    }

    render() {
      const { visible } = this.state;

      return (
        <div className="menu">
          { 
            visible &&
              <div className={this.props.alignment}>{this.props.children}</div>
          }
        </div>
      );
    }
}

If visible === true then the div will render, otherwise it won't. I removed the listeners, we don't do that in react, instead you need to define an onClick callback on the element that you want the user to click in order to hide the menu.

Upvotes: 4

Related Questions