- Published on
Using Ref with React Class Components and Styled-Components
- Authors
- Name
- Ripal & Zalak
How to Properly Use Ref with a React Class Component and Styled-Components
If you're working with styled-components
in a React class component and need to detect clicks outside a component, you might run into issues using refs. This guide will show you the proper way to use refs in class components with styled-components
.
The Problem
Using the old string-based ref API (this.refs.wrapper
) is deprecated and not recommended. Instead, you should use React.createRef()
, which allows you to directly reference the DOM node inside your component.
Here’s an example where we attempt to detect outside clicks but run into an issue with the old approach:
import React from 'react'
import styled, { ThemeProvider } from 'styled-components'
import { theme } from '../theme'
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 issue
}
handleClickInside = () => {
alert('Clicked inside')
}
render() {
return (
<ThemeProvider theme={theme}>
<Container>
<SelectorDiv onClick={this.handleClickInside} ref={'wrapper'}>
<h1>This is the content to click</h1>
</SelectorDiv>
</Container>
</ThemeProvider>
)
}
}
export default Test
React.createRef()
The Solution: Use To properly use refs in a React class component, follow these steps:
- Create a ref in the constructor using
React.createRef()
. - Attach it to the component using the
ref
attribute. - Access the DOM element using
this.ref.current
.
Here’s the corrected version of the above code:
import React from 'react'
import styled, { ThemeProvider } from 'styled-components'
import { theme } from '../theme'
const Container = styled.div`
display: flex;
`
const SelectorDiv = styled.div`
background-color: black;
color: white;
height: 100px;
`
class Test extends React.Component {
constructor(props) {
super(props)
this.selectorRef = React.createRef()
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside)
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside)
}
handleClickOutside = (event) => {
if (this.selectorRef.current && !this.selectorRef.current.contains(event.target)) {
console.log('Clicked outside')
}
}
handleClickInside = () => {
alert('Clicked inside')
}
render() {
return (
<ThemeProvider theme={theme}>
<Container>
<SelectorDiv onClick={this.handleClickInside} ref={this.selectorRef}>
<h1>This is the content to click</h1>
</SelectorDiv>
</Container>
</ThemeProvider>
)
}
}
export default Test
Key Improvements
- Uses
React.createRef()
to store the reference. - Attaches the ref properly using
ref={this.selectorRef}
. - Checks if the click is outside the component using
this.selectorRef.current.contains(event.target)
.
FAQs
useRef
instead?
1. Can I use No, useRef
is a React Hook, which only works in functional components. If you are using class components, React.createRef()
is the way to go.
2. What if I need multiple refs?
You can create multiple refs inside the constructor:
this.ref1 = React.createRef()
this.ref2 = React.createRef()
Then attach them individually.
this.selectorRef.current
is null
?
3. What happens if This can happen if the ref is not attached yet. Make sure to check if this.selectorRef.current
exists before accessing it.