I am trying to build a dropdown menu. The base structure Test
is where I need to detect clicks outside the content area using React ref
and styled-components
.
I have checked the related articles in SO but they use hooks not supported on my class component.
Here is the code:
import React from "react";
import PropTypes from "prop-types";
import styled, { ThemeProvider } from "styled-components";
import { theme } from "../theme";
import Icon from "../Icon";
const Container = styled.div`
display: flex;
`};
const SelectorDiv = styled.div`
background-color: black;
color: white;
height: 100px;
`;
class Test extends React.Component {
componentDidMount () {
document.addEventListener("mousedown", this.handleClickOutside);
}
componentWillUnmount () {
document.removeEventListener("mousedown", this.handleClickOutside);
}
handleClickOutside = event => {
console.log(this.refs); // undefined
}
handleClickInside = () => {
alert("Clicked inside");
}
render = () => {
return (
<ThemeProvider theme={theme}>
<Container disabled={disabled}>
<SelectorDiv
onClick={this.handleClickInside}
ref={"wrapper"}
>
<h1>This is the content to click</h1>
</SelectorDiv>
</Container>
</ThemeProvider>
);
};
}
export default Test;
The ref is not working property. When clicking outside the are I'm getting undefined
on this.refs
. Seens that styled-components
had issues with this, but it was solved on V4 (I'm using V5.1.0).
How to get the wrapper component inside my handleOutsideClick
?
Using ref as a string as you tried is a legacy way of React older API.
And they don't recommended using that:
If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases.
Note: If you’re currently using this.refs.textInput to access refs, we recommend using either the callback pattern or the createRef API instead.
use React.createRef()
instead,
And you can access it with current
attribute of the ref variable like so:
class Test extends React.Component {
constructor() {
super(props);
this.selectorRef = React.createRef(null);
}
componentDidMount() {
document.addEventListener("mousedown", this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClickOutside);
}
handleClickOutside = event => {
console.log(this.selectorRef.current);
}
handleClickInside = () => {
alert("Clicked inside")
}
render = () => {
return (
<ThemeProvider theme={theme}>
<Container disabled={disabled}>
<SelectorDiv
onClick={this.handleClickInside}
ref={ this.selectorRef }
>
<h1>This is the content to click</h1>
</SelectorDiv>
</Container>
</ThemeProvider>
);
};
}
export default Test;
Check it on sandBox
In functional components you can use React hook useRef()