Dropdown React&终极版

时间:2016-07-18 22:35:24

标签: javascript reactjs redux

如何打开一个,然后打开另一个。当你点击另一个区域时,它们就被关闭了。

React下拉代码:

<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>

关于redux下拉代码:

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 个答案:

答案 0 :(得分:2)

由于组件本地的注释状态可以保留在组件中。另一方面,要求下拉列表外的点击应该关闭下拉列表(或者更确切地说是所有下拉列表)将再次暗示全局状态(因为它本质上是页面的属性,而不是下拉列表)。因此,正确的redux方法是引用商店中当前打开的下拉列表以及重置该下拉列表的文档或窗口上的单击处理程序。这样,任何额外的下拉菜单也会将自己设置为商店的开放下拉列表,自动关闭其他任何下拉列表。

但我仍然不喜欢使用这种UI状态数据使我的商店复杂化,所以我最近创建了一个Dropdown类,它使用本地状态和文档事件的组合来处理“任何时候只打开一个下拉列表”处理程序。这是该组件的一个非常简化的版本(此处也可以作为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')
);

基本上,下拉列表根据本地状态呈现它的子项。下拉切换是它自己的状态。任何对页面的点击都会导致触发一个事件,每个组件都会检查它是否触发了事件本身,如果没有,它会自行关闭。