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. If you're currently using this. refs. textInput to access refs, we recommend the callback pattern instead.
It is a general rule of thumb to avoid using refs unless you absolutely have to. The official React documentation outlined only three possible use cases where refs are entirely considered useful for lack of better alternatives: Managing focus, text selection, or media playback. Triggering imperative animations.
Refs are a function provided by React to access the DOM element and the React element that you might have created on your own. They are used in cases where we want to change the value of a child component, without making use of props and all.
And since changing ref doesn't cause the component to re-render, the button stays active. To demonstrate this point further, let's add a parent component. By default when you render a React component it recursively re-renders all its children.
The Lint rule you are referring to is called no-string-refs and warns you with:
"Using string literals in ref attributes is deprecated (react/no-string-refs)"
You are getting this warning because have implemented the deprecated way of using refs
(by using strings). Depending on your React version, you can do:
constructor() {
super();
this.btnRef= React.createRef();
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div>
<div onClick={this.addVote}><span ref={this.btnRef} className="glyphicon"> </span></div>
</div>
);
}
constructor() {
super();
this.btnRef; //not necessary to declare the variable here, but I like to make it more visible.
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div>
<div onClick={this.addVote}><span ref={(el) => this.btnRef = el} className="glyphicon"> </span></div>
</div>
);
}
For even better readability, you could also do:
render() {
let myRef = (el) => this.btnRef = el;
return (
<div>
<div onClick={this.addVote}><span ref={myRef} className="glyphicon"> </span></div>
</div>
);
}
Have a look at what the official documentation says on Refs and the DOM, and this section in particular:
Legacy API: String Refs
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 asthis.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. If you're currently usingthis.refs.textInput
to access refs, we recommend the callback pattern instead.
The reason this ESLint rule exists is that string Refs are on their way out. However, for the code above I would recommend to not use a Ref in the first place.
React's advantage is that it is declarative. Meaning, we have state and an expression (returned JSX) of how the UI (more precisely the DOM) should look given a certain state.
Whatever can be done using just state and UI expression, should be done this way. The problem with the use of a Ref in the code above is that it makes the code imperative. We can't understand how the DOM will look just from the JSX. Here is how you could achieve the same result in a declarative way:
export class myComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
};
}
handleClick = () => { // with arrow function there is no need for binding.
this.setState(
prevState => {
return {
active: !prevState.active
}
}
)
}
render() {
return (
<div>
<span
onClick={this.handleClick}
className={`glyphicon ${this.state.active && "active"}`}
>
Hello World
</span>
</div>
);
}
}
Refs should be used when state and UI expression aren't enough, and you need access to the actual DOM. For example, focusing on an input field, scrolling to an element, or getting the exact width and height of an element.
String refs harm performance, aren't composable, and are on there way out.
string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. [Official React documentation]
[resource1][1], [resource2][1]
Option #1: Use React.createRef
class MyComponent extends Component {
constructor(props) {
super(props)
this.myRef = React.createRef() // create a ref object
}
render() {
return <div ref={this.myRef}></div> // Attach the ref property to a dom element
}
}
Option #2: Use a ref callback
class MyComponent extends Component {
constructor(props){ // Optional, declare a class field
super(props)
this.myRef=null
}
render() {
return <div ref={ (ref) => this.myRef=ref }></div>
} // Attach the dom element to a class field
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With