Reputation: 705
So i'm trying to make dropdown option component. I want to show it by clicking on the button, and hide it if click was detected outside of this component.
Here is a code. I made ref, but i cant understand how to check if click was on component or not:
import React, { Component } from 'react'
import './OptionsMenu.sass'
import DropdownBox from '../DropdownBox/DropdownBox'
import Icon from '../Icon/Icon'
class OptionsMenu extends Component {
constructor(){
super()
this.dropdownBoxRef = React.createRef()
}
handleClickOutside = event => {
if (this.dropdownBoxRef && !this.dropdownBoxRef.contains(event.target)) {
this.props.close()
}
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside)
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside)
}
render() {
const options = this.props.options.map(option => (
<li className='OptionsList-Element'>
<div className='OptionsList-ElementIcon'>
<Icon name={option.icon} />
</div>
<span>{option.label}</span>
</li>
))
return (
<DropdownBox ref={this.dropdownBoxRef} styles={this.props.styles}>
<ul className='OptionsList'>{options}</ul>
</DropdownBox>
)
}
}
export default OptionsMenu
With this code i have error: OptionsMenu.js:14 Uncaught TypeError: _this.dropdownBoxRef.contains is not a function
I know the error, cause it has not .contains(). So what to i must try to use?
Upvotes: 1
Views: 1507
Reputation: 3934
Please find the updated code that helps to solve your issue:
import ReactDOM from "react-dom";
import "./styles.css";
import React, { Component } from "react";
class OptionsMenu extends Component {
constructor() {
super();
this.dropdownBoxRef = React.createRef();
}
handleClickOutside = event => {
if (this.dropdownBoxRef && !this.dropdownBoxRef.current.contains(event.target)) {
this.props.close();
}
};
componentDidMount() {
document.addEventListener("mousedown", this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClickOutside);
}
render() {
const options = ["a", "b", "c"].map(option => (
<li className="OptionsList-Element">
<div className="OptionsList-ElementIcon">Icon</div>
<span>{option.label}</span>
</li>
));
return (
<div ref={this.dropdownBoxRef} styles={this.props.styles}>
<ul className="OptionsList">{options}</ul>
</div>
);
}
}
export default OptionsMenu;
const rootElement = document.getElementById("root");
ReactDOM.render(<OptionsMenu />, rootElement);
Note: this.dropdownBoxRef.current.contains(event.target) line is the game changer.
Upvotes: 1
Reputation: 4439
Refs have things stored inside a property called current
. So in order to actually reach your element you'll have to do this.dropdownBoxRef.current
and call .contains
on that.
Upvotes: 0