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.