ReactJS - Refs and the DOM
Hello, future React developers! Today, we're going to dive into an exciting topic that will help you interact directly with DOM elements in your React applications. Buckle up, because we're about to explore the world of Refs and the DOM!
What are Refs?
Before we jump into the nitty-gritty, let's understand what Refs are. In React, "Ref" is short for "reference". It's like giving a name tag to a specific element so you can easily find it later. Imagine you're at a big party, and you want to keep track of your best friend. You might give them a special hat or a unique name tag. That's essentially what a Ref does in React - it helps you keep track of specific elements.
Why do we need Refs?
You might be wondering, "Why can't we just use regular JavaScript to select elements?" Well, in React, we try to avoid directly manipulating the DOM (Document Object Model) because React has its own efficient way of updating the UI. However, there are times when we need to step outside of React's declarative paradigm and work directly with DOM elements. This is where Refs come in handy!
Creating Refs with createRef()
Let's start by looking at how we create a Ref in React. We use a method called createRef()
.
Signature of the createRef method
The signature of createRef()
is quite simple:
React.createRef()
That's it! No parameters, no complications. It returns a plain object with a single property: current
. Initially, this current
property is set to null
.
Let's see an example:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
In this example, we create a Ref in the constructor and assign it to this.myRef
. Then in the render
method, we attach this Ref to a div
element using the ref
attribute.
Applying ref
Now that we've created our Ref, let's see how we can use it. There are a few ways to apply a Ref:
1. Refs on DOM Elements
The most common use case is to apply a Ref to a DOM element:
class AutoFocusInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return <input ref={this.inputRef} />;
}
}
In this example, we create a Ref for an input element. After the component mounts, we use the Ref to automatically focus on the input. The current
property of the Ref gives us access to the actual DOM node.
2. Refs on Class Components
You can also use Refs with class components:
class AutoScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
componentDidUpdate() {
const node = this.listRef.current;
node.scrollToItem(0);
}
render() {
return <MyListComponent ref={this.listRef} />;
}
}
In this case, this.listRef.current
will point to the instance of the MyListComponent
class.
3. Refs and Functional Components
Functional components can't be given Refs directly, but you can use the forwardRef
function to pass Refs through:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}
render() {
return <FancyButton ref={this.buttonRef}>Click me!</FancyButton>;
}
}
In this example, FancyButton
uses forwardRef
to pass the Ref down to the actual button element.
Use cases of createRef
Now that we know how to create and apply Refs, let's look at some common use cases:
1. Managing focus, text selection, or media playback
class TextInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
focusTextInput = () => {
this.inputRef.current.focus();
}
render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.focusTextInput}>Focus the input</button>
</div>
);
}
}
This component allows us to programmatically focus the input when the button is clicked.
2. Triggering imperative animations
class Animator extends React.Component {
constructor(props) {
super(props);
this.elementRef = React.createRef();
}
animate = () => {
this.elementRef.current.classList.add('animated');
}
render() {
return (
<div>
<div ref={this.elementRef}>Animate me!</div>
<button onClick={this.animate}>Start Animation</button>
</div>
);
}
}
Here, we use a Ref to add a CSS class to an element, triggering an animation.
3. Integrating with third-party DOM libraries
class MapComponent extends React.Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}
componentDidMount() {
const mapLibrary = new FancyMapLibrary();
mapLibrary.createMap(this.mapRef.current);
}
render() {
return <div ref={this.mapRef} style={{width: '100%', height: '400px'}} />;
}
}
In this example, we use a Ref to give a third-party map library access to a DOM node where it can render a map.
Conclusion
Refs are a powerful tool in React that allow us to step outside the declarative paradigm when necessary. They provide a way to access DOM nodes or React elements directly. However, it's important to use Refs judiciously. In most cases, you can achieve what you need through React's declarative APIs. But when you do need that extra bit of control, Refs are there to help!
Remember, with great power comes great responsibility. Use Refs wisely, and your React applications will thank you!
Here's a quick reference table of the methods we've discussed:
Method | Description | Example |
---|---|---|
React.createRef() |
Creates a ref object | this.myRef = React.createRef(); |
ref attribute |
Attaches a ref to a React element | <div ref={this.myRef} /> |
forwardRef |
Allows functional components to receive refs | const FancyButton = React.forwardRef((props, ref) => ...) |
Happy coding, and may your Refs always be current!
Credits: Image by storyset