question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Implement Better Refs API

See original GitHub issue

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.

I think that the solution must ultimately be some kind of first class ref that can be passed around. These refs can be chained to create multi-owner refs very efficiently. By creating this object for the ref, we can also get rid of keeping track of owners on descriptors. Saving perf for the common idiomatic case of not using refs. A secondary goal, which may or may not be as important is the idea of making the resolution of refs asynchronous so that you can respond after a batched flush/reconciliation.

The concept of a first class ref is basically a reference to an object that doesn’t exist yet. Luckily there’s a first class notion of this in the language already… It’s called a Promise. You create a new Ref instance which is just Promise object that will eventually resolve to the actual instance.

class Foo {

  myDivRef = React.createRef();

  handleTick() {
    this.myDivRef.then(myDivNode => {
      this.setState({ width: myDivNode.offsetWidth });
    });
  }

  render() {
    return (
      <C tick={this.handleTick}>
        <div ref={this.myDivRef} />
        <CustomComponent context={this.myDivRef} />
      </C>
    );
  }

}

Since this builds on top of Promises we would be able to get async/await language features that allow us to do something like this:

  async handleTick() {
    this.setState({ width: (await this.myDivRef).offsetWidth });
  }

This solves all those use cases AFAIK. The asynchronous API is a little difficult to deal with. But it makes it less weird than the alternative when batching is involved.

An unsolved problem is that refs can update to point to a different instance. In that case the Promise would need to be re-resolved. This is why Promises are not good enough and we ultimately need something like an Observable that can handle multiple values. We can’t wait for that spec though. Maybe we just allow our promises to be reset and if you call then(…) again, you get a new value?

Issue Analytics

  • State:closed
  • Created 9 years ago
  • Reactions:1
  • Comments:32 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
sebmarkbagecommented, Apr 16, 2014

Actually I had imagine that a component instance of a ReactDOMComponent could become the DOM node. This is still controversial though. The alternative is just an empty object with a getDOMNode method on it.

1reaction
sophiebitscommented, Apr 15, 2014

With this API you wrote out, there’s no way to get a component instance, only a DOM node; this means you can’t call methods, etc. on child components. Intentional?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Implement Better Refs API · Issue #1373 · facebook/react
An unsolved problem is that refs can update to point to a different instance. In that case the Promise would need to be...
Read more >
Refs and the DOM - React
Refs provide a way to access DOM nodes or React elements created in the render method. In the typical React dataflow, props are...
Read more >
A complete guide to React refs - LogRocket Blog
Learn how to use React refs, and why it's important to use them only when React can't handle a function call through its...
Read more >
Refs - Create - REST API (Azure DevOps Git) | Microsoft Learn
The class to represent a collection of REST reference links. id. integer. identityId. string. name. string.
Read more >
Using $ref - Swagger
OAS 3 This guide is for OpenAPI 3.0. Using $ref. When you document an API, it is common to have some features which...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found