简体   繁体   中英

How do you remove a class from elements inside a component in React.JS when clicking outside given component?

I am trying to emulate a behavior similar to clicking on the overlay when a Modal popup is open. When clicking outside the sidenav component, I want to close all elements that are currently in a flyout mode.

I have a multi-tier nested navigation menu that is stored in its own component, Sidebar . I have the following piece of code that handles clicks that occur outside the Sidebar component:

class Sidebar extends React.Component {
    ...
    handleClick = (e) => {
      if (this.node.contains(e.target)) {
        return;
      }
  
      console.log('outside');
    };
  
    componentDidMount() {
      window.addEventListener('mousedown', this.handleClick, false);
    }

    componentWillUnmount() {
      window.removeEventListener('mousedown', this.handleClick, false);
    }

    render() {
      return (
          <div
              ref={node => this.node = node}
              className="sidebar"
              data-color={this.props.bgColor}
              data-active-color={this.props.activeColor}
          >
          {renderSideBar()}
          </div>
      );
    }
    ...
}

This part works fine - but when the flyout menus get displayed on clicking a parent menu option, I would like it to close -any- flyout menus that are currently opened.

-|
 |
 - Menu Item 1
  |
  |-option 1 (currently open)
  |-option 2
 - Menu Item 2
  | 
  |-option 1 (closed)
  |-option 2 (closed, clicked to expand - this is when it should close [Menu Item 1/Option 1]

The menu items are generated using <li> tags when mapping the data object containing the menu structure.

Is there a way to basically select all registered objects that have the class of 'collapse' / aria-expanded="true" and remove it? Similar to how jQuery would select dom elements and manipulate them.

I know that this is not the premise in which React works, it is just an example of the behavior I want to emulate.

As far as I understand you want to modify the DOM subtree from another component. To achive your goal you can use ref .

Using ref is helpful when you want to access HtmlElement API directly - in my example I use animate() . Please, read the documentation as it describes more of ref use cases.

Below is the simple example of animating <Sidebar/> shrinking when user clicks on <Content /> .

 const { useRef } = React; function Main() { const sidebar = useRef(null); const handleClick = () => { sidebar.current.hide(); }; return ( <div className="main"> <Sidebar ref={sidebar} /> <Content onClick={handleClick} /> </div> ); } class Sidebar extends React.Component { constructor(props) { super(props); this.state = { visible: true }; this.show = this.show.bind(this); this.sidebar = React.createRef(null); } show() { if (.this.state.visible) { this.sidebar.current:animate( { flex, [1, 2]: "background-color", ["teal", "red"] }; 300 ). this:setState({ visible; true }). } } hide() { if (this.state.visible) { this.sidebar.current:animate( { flex, [2, 1]: "background-color", ["red", "teal"] }; 300 ). this:setState({ visible; false }). } } render() { return ( <div ref={this.sidebar} className={this.state?visible: "sidebar--visible". "sidebar"} onClick={this;show} > Sidebar </div> ); } } function Content({ onClick }) { return ( <div className="content" onClick={onClick}> Content </div> ). } ReactDOM,render(<Main />. document;getElementById("root"));
 .main { display: flex; height: 100vh; }.sidebar { flex: 1; background-color: teal; }.sidebar--visible { flex: 2; background-color: red; }.content { flex: 7; background-color: beige; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM