【问题标题】:Bootstrap dropdowns in ReactJS, only one open at a timeReactJS 中的引导下拉菜单,一次只打开一个
【发布时间】:2018-10-01 09:09:27
【问题描述】:

我有一个页面包含多个引导卡,每张卡都是一个组件,每个卡页脚也是一个组件。卡片页脚包含按钮。当您单击一个按钮时,将打开如下所示的下拉菜单

在我点击一个按钮的任何时候,其他下拉菜单都应该处于关闭状态。但它的发生是这样的......

要求:还有一件事是当我点击同一个按钮时,相应的下拉菜单应该关闭。

要求:当我点击下拉菜单中的任何项目时,相应的下拉菜单应关闭

我的架构如下所示

主页组件代码 -START

class HomePage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: [],
      activatedIdStoredInParent: ""
    };
  }
  toggleCountersMenu = (name) => {
    var name1 = name;
    this.setState((prevState) => {
      return {
        activatedIdStoredInParent: name1
      }
    });
  } 

  render() {
   
    const products = this.state.items.map((item, index) => {     
      return <div>
        <Card
          product={item}
          activatedIdStoredInParent={this.state.activatedIdStoredInParent}
          toggleCountersMenu={this.toggleCountersMenu}
        >
        </Card>;
      </div>
    });

    return (
      <div>
        <div className="card-columns">
          {products}
        </div>
      </div >
    );
  }
}

export default HomePage;

主页组件代码 - 结束

卡组件代码 - 开始

class Card extends React.Component {
    handleActionClick = (name) => {
        this.props.toggleCountersMenu(name);
    }
    render() {
        return (
            <div key={this.props.product.name}>
                <CardHeader product={this.props.product}  />
                <CardBody product={this.props.product}  />
                <CardFooter
                    product={this.props.product}                    
                    onActionItemClick={this.handleActionClick}
                    activatedIdStoredInParent={this.props.activatedIdStoredInParent}
                />
            </div>
        );
    }
}

export default Card;

卡片页脚组件代码 - 开始

class CardFooter extends React.Component {

    handleActionItemClick = (name) => {
        this.props.onActionItemClick(name);
    }

    render() {
        console.log('Card Footer Drop Down comp rendered');
        return (
            <div className=" card-footer text-center">
                <ButtonDropdown text="F" className="danger"
                    product={this.props.product}
                    onActionItemClick={this.handleActionItemClick}
                    activatedIdStoredInParent={this.props.activatedIdStoredInParent}
                ></ButtonDropdown>            
            </div>
        );
    }
}

export default CardFooter;

ButtonDropdown 组件代码 - 开始

class ButtonDropdown extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            open: false,
            show: ' none',
            localActivatedId: 'none'
        }
    }
    toggleOpen = (e) => {
        var name = e.target.name;

        this.setState((prevState, props) => {
            var item = {
                localActivatedId: name
            }
            if (props.activatedIdStoredInParent === name) {
                if (prevState.show === ' show') {
                    item.show = ' none';
                }
                else {
                    item.show = ' show';
                }
            }
            return item;
        });
        this.props.onActionItemClick(name);
    }

    numberClick = (e) => {
        var qty = e.target.innerText;
        this.setState((prevState, props) => {
            var item = {
                show: ' none'
            }
            return item;
        });
    }
    render() {
        return (
            <div className="btn-group" >
                <button type="button" className={`btn btn-${this.props.className}  mr-1`} name={this.props.product.name + '$$' + this.props.text} onClick={this.toggleOpen}>
                    {this.props.text} (classAdded={this.state.show})
                </button>
                
                <div className={`dropdown-menu ${this.state.show}`}>
                    <span className="dropdown-item cursor-pointer " onClick={this.numberClick}>
                        -1
                    </span>
                    <span className="dropdown-item cursor-pointer" onClick={this.numberClick}>
                        -2
                    </span>
                </div>
            </div>



        );
    }
}

export default ButtonDropdown;

当我在 Card Footer 中添加多个 buttonDropdown 组件时,最终产品是这样的。如何关闭其他下拉菜单。

我想知道我的架构是否正确。我没有使用 Redux/Flux 等。

【问题讨论】:

标签: reactjs react-bootstrap


【解决方案1】:

您可以使用componentDidUpdate 生命周期来更新您的状态属性,即打开下拉菜单。 我不知道是open 还是show 属性显示了下拉列表的内容,但这是我的逻辑。

class ButtonDropdown extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // 
    };
  }

  componentDidUpdate(prevProps) {
    const name = this.props.product.name + '$$' + this.props.text;

    if (prevProps.activatedIdStoredInParent !== this.props.activatedIdStoredInParent && this.props.activatedIdStoredInParent !== name) {
      this.closeDropDown();
    }
  }

  closeDropDown = () => this.setState({ isOpen: false });

  toggleOpen = (e) => {
    //
  }

  numberClick = (e) => {
   //
  }

  render() {
   //
  }
}

export default ButtonDropdown;

【讨论】:

  • 嗨,Soupette,谢谢您的回答。有效。如果你写在 componentDidUpdate 中,它每次都会调用,这将是性能问题。你说什么..你能解释一下吗..
  • 您可以使用PureComponent 来提高性能。关于 componentDidUpdate 的使用,除非您摆脱状态并仅使用父容器的道具,否则我看不到使用当前架构打开和关闭组件的另一种方法。
  • 感谢您的回复。 “除非您摆脱状态并仅使用父容器的道具”。这个架构到底是什么,你能告诉我吗?
  • const name = const name = this.props.product.name + '$$' + this.props.text; const show = name === this.props.activatedIdStoredInParent 然后在你的className中使用show变量
  • 如果我删除这个“this.props.activatedIdStoredInParent !== name”它会进入无限循环。如果我的 json 有更多像 10000 这样的对象,这段代码是否可行?
猜你喜欢
  • 2017-01-10
  • 2016-09-17
  • 1970-01-01
  • 2014-02-26
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
相关资源
最近更新 更多