首页 > 解决方案 > 在 React 中打开另一个对话框时如何自动关闭一个对话框

问题描述

TopButtonsBarComponent

我正在制作一个带有导航栏的反应应用程序,如上图所示。导航栏是一个名为“TopButtonsBar”的组件。在此 TopButtonsBar 组件内呈现的是上面每个按钮图片的组件。这些组件从左到右依次是 InfoButton、NotificationsButton 等。每个按钮组件都管理自己的状态,该状态指示是否应显示给定按钮的对话框。以下是按钮组件的外观,以 InfoButton 组件为例。

    export default class InfoButton extends React.Component{
    
    constructor(props){
        super(props);
        this.state = {
            isDialogueOpen:false,
            isHoveringOver:false
        };
        this.handleOpenDialogue = this.handleOpenDialogue.bind(this);
        this.handleHoverOver = this.handleHoverOver.bind(this);
    }
    
    **handleOpenDialogue = (e) => {
        e.preventDefault();
        this.setState((prevState) => ({
            isDialogueOpen:!prevState.isDialogueOpen
        }));
    }**
    handleHoverOver = (e) => {
        e.preventDefault();
        if(!this.state.isDialogueOpen){
            this.setState((prevState) => ({
                isHoveringOver:!prevState.isHoveringOver
            }));
        }
    }
    
    render(){
        return(
            <div className="navbar-button">
                <img 
                    onMouseOver={this.handleHoverOver} 
                    onMouseLeave={this.handleHoverOver} 
                    onClick={this.handleOpenDialogue}
                    src={this.state.isHoveringOver?infoButtonHovered:infoButtonNotHovered} alt="Info"
                />
                {this.state.isHoveringOver && !this.state.isDialogueOpen && <InfoRollover />}
                **{this.state.isDialogueOpen && <InfoDialogue />}**
            </div>
        )
    }
}

重要的位是 *用星号 * 括起来的。此逻辑在按钮单独级别上运行良好。我想要做的是:如果,如上图,选择了消息通知按钮,如果我点击信息按钮,我希望消息通知按钮关闭,同时信息按钮打开。但是,我在概念化我应该如何重新配置​​状态方面一直没有成功。如果任何按钮已关闭,TopButtonsBar 组件是否应该保存有关状态的信息?如果是这样,我将如何重新处理按钮的打开方式(以及单个按钮组件是否应该控制该状态)。另外,我没有使用任何状态管理器,例如 Redux、Hooks 等。谢谢!

标签: reactjsdialogmodal-dialogstate

解决方案


解决此问题的一种方法是在父组件的状态 ( ) 中拥有isDialogueOpen所有子组件 (InfoButton等) 的标志 (如)。NotificationButtonTopButtonsBar

TopButtonsBar.js

我将首先添加一些标识每个对话框的常量。之后,我们可以声明一个状态,该状态将指向打开的对话框。

只需遵循以下代码中的注释即可更好地理解。


// adding some constants here
const INFO_BUTTON = 'INFO_BUTTON';
const NOTIFICATION_BUTTON = 'NOTIFICATION_BUTTON';

export default class TopButtonsBar extends React.Component {
   constructor(props) {
      super(props);
      this.state = {
         ...
         // adding this state to point out which dialogue is open
         selectedDialogue: null
      }
   }
   
   handleOpenDialogue = (e, selectedDialogue) => {
      e.preventDefault();
      if (selectedDialogue === this.state.selectedDialogue) {
         // close dialogue if already open
         this.setState({selectedDialogue: null});
      } else {
         // else open this dialogue
         this.setState({selectedDialogue});
      }
   }
   
   ....
   render() {
      return (
          ....
          <InfoButton
               isDialogueOpen={this.state.selectedDialogue === INFO_BUTTON}
               handleOpenDialogue={(e) => handleOpenDialogue(e, INFO_BUTTON)}
               ...
          />
          <NotificationButton
               isDialogueOpen={this.state.selectedDialogue === NOTIFICATION_BUTTON}
               handleOpenDialogue={(e) => handleOpenDialogue(e, NOTIFICATION_BUTTON)}
               ...
          />
      )
   }
}

InfoButton.js

现在我们将组件的状态及其处理函数TopButtonsBar作为 props 传递,我们可以直接在InfoButtonand中调用它们NotificationButton,而无需任何相关的本地状态。

export default class InfoButton extends React.Component{
    
    constructor(props){
        super(props);
        this.state = {
            // removing the state from here
            isHoveringOver:false
        };
        this.handleHoverOver = this.handleHoverOver.bind(this);
    }
    
    // removing the handleOpenDialogue function here

    ...
    
    render(){
        return(
            <div className="navbar-button">
                <img 
                    onMouseOver={this.handleHoverOver} 
                    onMouseLeave={this.handleHoverOver}
                    // calling handleOpenDialogue from props
                    onClick={this.props.handleOpenDialogue}
                    ...
                />
                // using isDialogueOpen from props now
                {this.state.isHoveringOver && !this.props.isDialogueOpen && <InfoRollover />}
                {this.props.isDialogueOpen && <InfoDialogue />}
            </div>
        )
    }
}

推荐阅读