5

How do I get opened one, and then another. And that when you click to another area, they were closed.

React dropdown code:

<div className="header__nav">
          <div className={classnames('header__nav__title', { 'is-active' : this.props.navAuthors })} onClick={this.props.toggleNavAuthors}><FormattedMessage {...messages.authors} /></div>
          <ReactCSSTransitionGroup transitionName='header-menu-animation' transitionEnterTimeout={350} transitionLeave={false}>
            {this.props.navAuthors ? this._renderAuthors() : null}
          </ReactCSSTransitionGroup>
        </div>
        <div className="header__nav">
          <div className={classnames('header__nav__title', { 'is-active' : this.props.nav })} onClick={this.props.toggleNav}><FormattedMessage {...messages.typefaces} /></div>
          <ReactCSSTransitionGroup transitionName='header-menu-animation' transitionEnterTimeout={350} transitionLeave={false}>
            {this.props.nav ? this._renderTypefaces() : null}
          </ReactCSSTransitionGroup>
        </div>

on redux dropdown code:

import {
  SHOW_NAV,
  HIDE_NAV
} from '../constants/ActionTypes'

export function toggleNav() {
  return (dispatch, getState) => {
    const { nav } = getState()
    dispatch({
      type: nav ? HIDE_NAV : SHOW_NAV
    })
  }
}

export function hideNav() {
  return {
    type: HIDE_NAV
  }
}
1
  • this kind of local stuff can be managed inside the component without redux, its seams to get overcomplicated.. Commented Jul 18, 2016 at 22:50

1 Answer 1

3

As commented state such as this which is local to the component can be kept in the component. On the other hand a requirement that a click outside the dropdown should close the dropdown (or rather all dropdowns) would again imply global state (since it's essentially a property of the page, not the dropdown anymore). So the proper redux way would be to have a reference to the currently open dropdown in your store and a click handler on your document or window that resets that dropdown. This way any additional dropdowns would also just set themselves as the open dropdown on the store automatically closing any others.

But I still prefer not over complicating my store with this kind of UI state data, so I recently created a Dropdown class that handles the "only one dropdown open at the any time" using a combination of local state and a document event handler. Here's a very simplified version of this component (also available here as a fiddle).

// Choose a unique name for your event, this will be listened to by 
// all the dropdown components.
var EVENTNAME = "dropdown-close";

// The document triggers the event whenever anything is clicked
document.addEventListener('click', (e)=>
{
    window.dispatchEvent(new CustomEvent(EVENTNAME, { 
        // need to pass in the original element as reference
        // so the handler can check if it triggered it itself
        detail: e.srcElement
    }));
});

var DropDown = React.createClass({

    getInitialState: function() 
    {
        return {open: false};
    },

    render()
    {
        let menu = null;
        if (this.state.open) { 
            menu = this.props.children;
        }
        return <div className="dropdown">
            <a className="dropdown-toggle" ref="toggle" onClick={this.toggleMenu}>Dropdown</a>
            {menu}
        </div>
    },

    toggleMenu(e)
    {
        this.setState({open: !this.state.open});
    },

    closeMenu(e)
    {
        if (e.detail !== this.refs.toggle)
        {
            this.setState({open: false});
        }
    },

    componentWillMount()
    {
        var that = this;
        window.addEventListener(EVENTNAME, this.closeMenu);
    },

    componentWillUnmount()
    {
        var that = this;
        window.removeEventListener(EVENTNAME, this.closeMenu);
    }
});

ReactDOM.render(
  <div>
    <h1>First</h1>
    <DropDown>
      <li>Item 1 (in my case these are also React comps)</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </DropDown>
    <hr/>
    <h1>Second</h1>
    <DropDown>
      <li>Item 1 (in my case these are also React comps)</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </DropDown>
  </div>,
  document.getElementById('container')
);

Essentially the dropdown renders it's children based on local state. The dropdown toggle's it's own state. Any click on the page will cause an event to be triggered that each component checks to see if it triggered the event itself, if not it will close itself.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.