Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why ref='string' is "legacy"?

Tags:

reactjs

In the React documentation they say:

React also supports using a string (instead of a callback) as a ref prop on any component, although this approach is mostly legacy at this point.

https://facebook.github.io/react/docs/more-about-refs.html

Take the following example:

class Foo extends Component {
  render() {
    return <input onClick={() => this.action()} ref={input => (this._input = input)} />;
  }
  action() {
    console.log(this._input.value);
  }
}

Why should I prefer this, instead of:

class Foo extends Component {
  render() {
    return <input onClick={() => this.action()} ref='input' />;
  }
  action() {
    console.log(this.refs.input.value);
  }
}

?

It seems just much more clean and easier the second example.
Are there risks that the string method will be deprecated?


NB: I'm looking for the "official" answer to the statement in the documentation, I'm not asking about personal preferences and so on.

like image 309
Fez Vrasta Avatar asked May 26 '16 18:05

Fez Vrasta


People also ask

Why ref is not recommended in React?

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.

Why we use REF IN react native?

In react native, Refs help us to do that. As per React Documentation, it says - Refs provide a way to access DOM nodes or React elements created in the render method. Sometimes we need to change the properties of DOM without using state and props. In that case, we use Refs.

Why we may not use the ref attribute?

When the ref attribute is used on a custom class component, the ref object receives the mounted instance of the component as its current . You may not use the ref attribute on function components because they don't have instances.

Why do we use REF in JavaScript?

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.


2 Answers

While perhaps more simple, the old refs API can get difficult in some edge cases, like when used in a callback. All kind of static analysis is a pain with strings, too. The callback based API can do everything the string API can do and more with just a little added verbosity.

class Repeat extends React.Component {
  render() {
    return <ul> {
      [...Array(+this.props.times)].map((_, i) => {
        return <li key={i}> { this.props.template(i)    } </li>
      })
    } </ul>
  }
}

class Hello extends React.Component {
  constructor() {
    super();
    this.refDict = {};
  }

  render() {
    return <Repeat times="3" template={i => <span ref= {el => this.refDict[i] = el}> Hello {i} </span>} />
           {/*                                    ^^^ Try doing this with the string API          */}
  }
}

Further discussion and a bit more comprehensive list of the possible issues with the string based api can be found from issue #1373, where the callback based api was introduced. I'll include here a list from the issue description:

The ref API is broken is several aspects.

  • You have to refer to this.refs['myname'] as strings to be Closure Compiler Advanced Mode compatible.

  • It doesn't allow the notion of multiple owners of a single instance.

  • Magical dynamic strings potentially break optimizations in VMs.

  • It needs to be always consistent, because it's synchronously resolved. This means that asynchronous batching of rendering introduces potential bugs.

  • We currently have a hook to get sibling refs so that you can have one component refer to it's sibling as a context reference. This only works one level. This breaks the ability to wrap one of those in an encapsulation.

  • It can't be statically typed. You have to cast it at any use in languages like TypeScript.

  • There's no way to attach the ref to the correct "owner" in a callback invoked by a child. <Child renderer={index => <div ref="test">{index}</div>} /> -- this ref will be attached where the callback is issued, not in the current owner.


The docs call the old string API "legacy" to make it clearer that the callback-based API is the preferred approach, as is discussed in this commit and in this PR which are the ones that actually put those statements to the documentation in the first place. Also note that a few of the comments imply that the string based refs api might be deprecated at some point.

like image 108
noppa Avatar answered Oct 10 '22 17:10

noppa


Originally posted by danabramov on https://news.ycombinator.com/edit?id=12093234

  1. String refs are not composable. A wrapping component can’t “snoop” on a ref to a child if it already has an existing string ref. On the other hand, callback refs don’t have a single owner, so you can always compose them.
  2. String refs don’t work with static analysis like Flow. Flow can’t guess the magic that framework does to make the string ref “appear” on this.refs, as well as its type (which could be different). Callback refs are friendlier to static analysis.
  3. The owner for a string ref is determined by the currently executing component. This means that with a common “render callback” pattern (e.g. <DataTable renderRow={this.renderRow} />), the wrong component will own the ref (it will end up on DataTable instead of your component defining renderRow).
  4. String refs force React to keep track of currently executing component. This is problematic because it makes react module stateful, and thus causes weird errors when react module is duplicated in the bundle.
like image 18
pizzarob Avatar answered Oct 10 '22 17:10

pizzarob