Using ‘ref’ in React
People coming to React, after spending good amount of time in jquery or vanilla javascript, will have to undergo a few painful unlearning. One thing that comes at the top of the list is, we should not use global selectors like document.querySelector() or document.getElementById().
Your react app may still work while having these global selectors, but it is considered as a top rated bad practice.
Why?
As we have heard lot of times earlier, everything in React is a component. And each component works independently and they have self-contained code. But global selectors don’t search just on your component, they search at global document level, and fetches the dom that may belong to some other component. And this will lead to lots of unpredictable bugs.
A very simple example would be, if we have two instances of the same component, the selector for the second instance may fetch the dom nodes from the first instance, which is totally unexpected.
The React Way
React advises to use ‘state’ to map dom with the variables. Ofcourse it provides lots of advantages like ‘single source of truth’, instant validation, fewer bugs etc. But the down side is, it is a bit time consuming, when we are in a hurry to build something quick and fast.
There are some valid use cases where we don’t want to do it in the react way. One example is, say we have a form, and we don’t want to do instant validation on every fields, and we just want to read the field values on submit button.
In case, if you don’t want to map your dom with state, (for whatever reason it may be) react provides an alternative.
ref
Put simply, ‘ref’ is used to identify dom nodes in a component.
<input type= "text" ref={ n => {this.myRef = n }} />
In the above example ‘this.myRef’ will have the reference of the text input field. Its value is assigned through a callback function, which is quite understandable. The dom node will not be available at the time of rendering. It will be available only after rendering, and the callback function assigned to ‘ref’ will be called then.
Note: Since we are not mapping state with dom, we cannot use this.setState() to update. In this situation, we will have some component level variables (not state variables) and update them whenever needed, and to re-render the component we will call this.forceUpdate()
When the component size becomes large, we may want to refactor our component and move our ‘ref’ to our child component.
In parent component:
<Child childComponentRef={ n => this.childComponentRef = n} />
In child component:
<input type = "text" ref={props.childComponentRef} />
Please refer this snippetfor the complete example.
Here, the ‘ref’ attribute is mapped with a props variable instead of a callback function. This is the important difference to keep in mind. But the props variable itself is a callback function present in the parent component. (This logic will take sometime for new developers to sink in). But believe me, it is just too straight forward. Refs are associated with a callback function, which will be called once the rendering completes.
Note: React advises to use ‘ref’ sparingly