We know that when we want to modify a child in React, we use props and re-render a child with new props to change the child. But sometimes we need to change the child apart from the standard data flow and in such cases, we need to use refs. So we can say that refs help us in accessing the DOM nodes or the React elements which are created in the render method.
We can use refs when managing focus, text selection, or media playback. Also, refs are helpful when we need to trigger imperative animations or when we need to integrate with third-party DOM libraries.
We should not use refs unnecessarily, they should not be used for any cases which can be done declaratively. Before using refs we should first think properly about how we can put states in the hierarchy so that we don’t need to use refs.
React provides us with createRef()
. With the help of that method we can create refs and then we need to attach the create ref with React element which can be done using the ref attribute. And for the functional components, we need to use the useRef()
hook with a null value as the initial value. Most of the time, we need to assign the refs with instance property which is done when a component is created such that we can reference them throughout the component.
1
2
3
4
5
6
7
8
9
class DemoComp extends Component {
constructor(props) {
super(props);
this.newRef = React.createRef();
}
render() {
return <div ref={this.newRef} />;
}
}
We can access the reference to the node by passing a ref to an element in the render, which will then be accessible at the current attribute of the ref.
1
const refNode = this.newRef.current;
Based on the type of the node the value of ref will be different. For example, when the ref attribute is used on the HTML element then ref inside the constructor of createRef()
will get the DOM element as the ‘current’ property. And for the custom class component, if we want to use the ref attribute then, in this case, the ‘current’ of the ref object will have the mounted instance of the component. Also, with function components, we cannot use the ref attributes since they don’t have any instances. Let’s see each one of these cases separately.
To add ref to a DOM element we need to pass the ref attribute and in this case, the ‘current’ property will be assigned with the DOM element when the component mounts. After that, React will assign the ‘current’ property again to null when the DOM element unmounts. And before componentDidMount and componentDidUpdate lifecycle, this update of ref happens. The example below shows the addition of ref to DOM element.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class myComponent extends Component {
constructor(props) {
super(props);
this.refInput = React.createRef(); //create ref
this.focusInputText = this.focusInputText.bind(this); //to bind this keyword
}
focusInputText() {
this.refInput.current.focus(); // to focus input using DOM API
}
render() {
return (
<div>
{/* To associate the refInput in constructor with <input> */}
<input type="text" ref={this.refInput} />
<input type="button" value="Click to Focus input" onClick={this.focusInputText} />
</div>
);
}
}
Only when we are using a class component, if we want to simulate that the refInput is clicked just after mounting, then in this case, we can call the focusInputText method manually and use the ref to get access to the myComponent.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class AutoFocusComp extends Component {
constructor(props) {
super(props);
this.refInput = React.createRef(); //create ref
}
componentDidMount() {
this.refInput.current.focusInputText(); //manually call focusInputText method
}
render() {
//to associate the ref with our component
return (
<myComponent ref={this.refInput} />
);
}
}
We cannot actually directly use the ref attribute on the function component since we know that the function component doesn’t have any instances. So, if we want to use ref we must use the forwardRef, otherwise we need to convert this component to a class component. But if we just want to refer to the DOM element or a class component inside the function component then in this case, we can use the ref attribute.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function myComponent(props) {
const refInput = useRef(null); //for functional component we need to use useRef
function clickHandler() {
refInput.current.focus(); //to focus input
}
return (
<div>
{/* To associate the refInput in constructor with <input> */}
<input type="text" ref={refInput} />
<input type="button" value="Click to Focus input" onClick={clickHandler} />
</div>
);
}