-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Add React.createRef doc #637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Deploy preview for reactjs ready! Built with commit f6e5d65 |
First deploy attempt failed because of the same transient Sharp.node issue:
This module is such a pain. Restarting the build without cache. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some thoughts 😄
content/docs/refs-and-the-dom.md
Outdated
React supports a special attribute that you can attach to any component. The `ref` attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted. | ||
|
||
When the `ref` attribute is used on an HTML element, the `ref` callback receives the underlying DOM element as its argument. For example, this code uses the `ref` callback to store a reference to a DOM node: | ||
When the `ref` attribute is used on an HTML element, the `ref` created in the constructor with `React.createRef()` receives the underlying DOM element as its `value` property. For example, this code uses a `ref` to store a reference to a DOM node: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this introduction to createRef
could be clearer.
Maybe split this into two sentences? First, introduce React.createRef()
and explain that you use it either in the constructor or via a property initializer. Then explain that you pass it to the ref
attribute etc.
|
||
```javascript{8,9,19} | ||
class CustomTextInput extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
// create a ref to store the textInput DOM element | ||
this.textInput = React.createRef(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes break the line highlighting above
javascript{8,9,19}
You'll want to update the line number offsets.
Might also be a nice time to move these examples into the "examples" folder so Prettier can manage the formatting for us. (Totally optional though.) This would allow you to use the nicer "highlight-line" and "highlight-range" directives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. 👍
content/docs/refs-and-the-dom.md
Outdated
// Use the `ref` callback to store a reference to the text input DOM | ||
// element in an instance field (for example, this.textInput). | ||
// tell React that we want the associate the <input> ref | ||
// to the `textInput` that we created in the constructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"associate with" rather than "associate to"?
Or maybe better yet:
// Tell React to store a reference to the text input DOM
// element in thetextInput
ref we created in the constructor.
content/docs/refs-and-the-dom.md
Outdated
|
||
```javascript{3,9} | ||
class AutoFocusTextInput extends React.Component { | ||
constructor(props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about the line highlights being off here.
@@ -107,11 +115,14 @@ function MyFunctionalComponent() { | |||
} | |||
|
|||
class Parent extends React.Component { | |||
constructor(props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line highlights are off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. 👍
constructor(props) { | ||
super(props); | ||
this.inputElement = React.createRef(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line highlights are off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed 👍
content/docs/refs-and-the-dom.md
Outdated
<Parent | ||
inputRef={el => this.inputElement = el} | ||
/> | ||
<Parent inputRef={this.inputElement} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line highlights are off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed 👍
content/docs/refs-and-the-dom.md
Outdated
|
||
All things considered, we advise against exposing DOM nodes whenever possible, but this can be a useful escape hatch. Note that this approach requires you to add some code to the child component. If you have absolutely no control over the child component implementation, your last option is to use [`findDOMNode()`](/docs/react-dom.html#finddomnode), but it is discouraged. | ||
|
||
### Callback Refs | ||
|
||
The above examples use `React.createRef()`, which can be thought of as "object refs". React also supports an alternative approach called "callback refs", which offer the same functionality as object refs, but also also give more fine-grain control over when refs are set and unset. In much the same way object refs work, callback refs can be used in a similar approach. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In much the same way object refs work, callback refs can be used in a similar approach.
This sentence seems redundant. Maybe:
Callback refs work in much the same way as object refs.
content/docs/refs-and-the-dom.md
Outdated
|
||
The above examples use `React.createRef()`, which can be thought of as "object refs". React also supports an alternative approach called "callback refs", which offer the same functionality as object refs, but also also give more fine-grain control over when refs are set and unset. In much the same way object refs work, callback refs can be used in a similar approach. | ||
|
||
With callback refs, instead of creating a ref with `React.createRef()`, you instead pass normal JavaScript functions to `ref` attributes. When the `ref` attribute is used on an HTML element, the `ref` callback receives the underlying DOM element as its argument. For example, this code uses the `ref` callback to store a reference to a DOM node: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Too many "instead"s in the first sentence. Remove the second one?
content/docs/refs-and-the-dom.md
Outdated
<div> | ||
<input | ||
type="text" | ||
ref={(input) => { this.textInput = input; }} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious if theres' any reason we bind focusTextInput
but use an inline arrow function for the ref-setter? Maybe consistency one way or the other might be nice?
In this case, maybe bind the ref setter so the next paragraph is more accurate? (The inline setter will get called for each update too.)
Also the third paragraph, showing the "shorter way" would maybe be more meaningful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The examples were the same as before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think we could improve them 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think this, by the way. I don't think it's really a performance concern, but I think there's a tiny chance of confusion here. React will unset the old ref and re-set the new ref each render cycle, which I have known to confuse people in the past.
We even mention this as a caveat below. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
content/docs/refs-and-the-dom.md
Outdated
React supports a special attribute that you can attach to any component. The `ref` attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted. | ||
>**Note:** | ||
> | ||
>The examples below have updated to use the new `React.createRef()` API, introduced in React 16.3. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will read a little weird in a few months when createRef
is no longer new.
The examples below use the
React.createRef()
API introduced in React 16.3.
content/docs/refs-and-the-dom.md
Outdated
|
||
```javascript{8,9,19} | ||
Refs can be created using `React.createRef()` and are commonly assigned to a component class instance in the constructor or via a property initializer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit hard to grok this initial example without context. How about leading with the second one that includes the render method?
Even better may be the canonical "autofocus an input" example that shows how to use a ref end-to-end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we could keep the sentences separate (I like them) but maybe just have one code example (that highlights both lines)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commonly assigned to a component class instance in the constructor or via a property initializer.
Shouldn't it be instance property?
Refs can be created using
React.createRef()
and are commonly assigned to an instance property when a component is constructed. (Avoids going into class property vs constructor details).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dig that.
content/docs/refs-and-the-dom.md
Outdated
|
||
All things considered, we advise against exposing DOM nodes whenever possible, but this can be a useful escape hatch. Note that this approach requires you to add some code to the child component. If you have absolutely no control over the child component implementation, your last option is to use [`findDOMNode()`](/docs/react-dom.html#finddomnode), but it is discouraged. | ||
|
||
### Callback Refs | ||
|
||
The above examples use `React.createRef()`, which can be thought of as "object refs". React also supports an alternative approach called "callback refs", which offer the same functionality as object refs, but also also give more fine-grain control over when refs are set and unset. Callback refs work in much the same way as object refs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this part could be more direct:
React also supports another way to set refs called "callback refs", which give more fine-grain control over when refs are set and unset.
Instead of passing a
ref
attribute created bycreateRef
, you pass a function. The function receives the React component instance or HTML DOM element as its argument, which can be stored and accessed elsewhere. This example uses theref
callback to store a reference to a DOM node:
<example>
content/docs/refs-and-the-dom.md
Outdated
|
||
React will call the `ref` callback with the DOM element when the component mounts, and call it with `null` when it unmounts. `ref` callbacks are invoked before `componentDidMount` or `componentDidUpdate` lifecycle hooks. | ||
|
||
Using the `ref` callback just to set a property on the class is a common pattern for accessing DOM elements. The preferred way is to set the property in the `ref` callback like in the above example. There is even a shorter way to write it: `ref={input => this.textInput = input}`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why "just"?
content/docs/refs-and-the-dom.md
Outdated
this.focusTextInput = this.focusTextInput.bind(this); | ||
} | ||
|
||
focusTextInput() { | ||
// Explicitly focus the text input using the raw DOM API | ||
this.textInput.focus(); | ||
this.textInput.value.focus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback @alexkrolick @bvaughn. I've addressed (hopefully) all the feedback. Let me know if I missed something. |
Nice, I'll look through it again 👍 |
createRef tweaks and suggestions
@trueadm making a few more suggestions in PRs EDIT: I'll open another one 😛 |
@alexkrolick Sorry, I didn't realize it was a work in progress :P |
@trueadm all done 😄 |
Create "Accessing refs" section above specific examples
@alexkrolick Thanks for the help! @bvaughn want to give it once last proof check? If I merge, will this go to the versioned 16.3 site or do we have to wait? |
Will try to look tomorrow on my flight back. Don't merge until we release 16.3 though, or it will go live on the site (before the actual API is live) 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Back to you with some minor suggestions.
content/docs/refs-and-the-dom.md
Outdated
@@ -11,6 +11,8 @@ redirect_from: | |||
permalink: docs/refs-and-the-dom.html | |||
--- | |||
|
|||
Refs provide a way to access DOM nodes and React elements created by React by getting a _reference_ to the element in the render method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's something awkward about this wording.
"React elements created by React" sounds a bit redundant and "getting a reference to the element in the render method" sounds potentially misleading (since refs are rarely used in render
in my experience).
Maybe something simpler? Like:
Refs provide a way to access DOM nodes or React elements created in the
render
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be obvious, but at some point in the page it should probably say that "ref" is short for "reference"... 💭
content/docs/refs-and-the-dom.md
Outdated
### Adding a Ref to a DOM Element | ||
>**Note:** | ||
> | ||
>The examples below have updated to use the `React.createRef()` API introduced in React 16.3. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The examples below have updated to use...
Missing word? Should be "have been updated"?
Also I think it might be worth adding a second sentence:
The examples below have been updated to use the
React.createRef()
API introduced in React 16.3. If you are using an earlier release of React, we recommend using [#callback-refs](callback refs) instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
content/docs/refs-and-the-dom.md
Outdated
|
||
```javascript{8,9,19} | ||
The value of the ref differs depending on whether the node is an HTML DOM node, a React class component instance, or a stateless functional component: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should maybe drop the "or a stateless functional component" bit in this sentence. It seems a little confusing, since you can't actually use a ref in this case. (I think we should leave the bullet point below that explicitly states this.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value of the ref differs depending on the type of the node: ... bullets...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
content/docs/refs-and-the-dom.md
Outdated
The value of the ref differs depending on whether the node is an HTML DOM node, a React class component instance, or a stateless functional component: | ||
|
||
- When the `ref` attribute is used on an HTML element, the `ref` created in the constructor with `React.createRef()` receives the underlying DOM element as its `value` property. | ||
- When the `ref` attribute is used on a custom component declared as a class, the `ref` object receives the mounted instance of the component as its `value`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording nit. Maybe:
When the
ref
attribute is used on a custom class component, theref
object receives the mounted instance of the component as itsvalue
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
### Accessing Refs | ||
|
||
When a ref is passed to an element in `render`, a reference to the node becomes accessible at the `value` attribute of the ref. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording nit: We have a lot of sentences with both "ref" and "reference". It's fine, but I wonder if it might read better if we swapped "reference" with "pointer" in some of these places?
When a ref is passed to an element in
render
, a pointer to the node becomes accessible at thevalue
attribute of the ref.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe... but pointer isn't particularly common terminology in JS-land so I'd worry it might confuse some people.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Terms like "pointer" and "reference" aren't just used in programming. I think they have broader meaning outside of programming that's relevant.
Maybe someone like @gaearon could weigh-in with an opinion about non-native English speakers and if there are concerns there though. I have no idea.
content/docs/refs-and-the-dom.md
Outdated
); | ||
} | ||
} | ||
``` | ||
|
||
Here, the ref callback is first specified by `Grandparent`. It is passed to the `Parent` as a regular prop called `inputRef`, and the `Parent` passes it to the `CustomTextInput` as a prop too. Finally, the `CustomTextInput` reads the `inputRef` prop and attaches the passed function as a `ref` attribute to the `<input>`. As a result, `this.inputElement` in `Grandparent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`. | ||
Here, the ref `this.inputElement` is first specified by `Grandparent`. It is passed to the `Parent` as a regular prop called `inputRef`, and the `Parent` passes it to the `CustomTextInput` as a prop too. Finally, the `CustomTextInput` reads the `inputRef` prop and attaches the passed ref as a `ref` attribute to the `<input>`. As a result, `this.inputElement.value` in `Grandparent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Same thought here as above w.r.t. this.inputElement
reading simpler as this.inputRef
.
content/docs/refs-and-the-dom.md
Outdated
); | ||
} | ||
} | ||
``` | ||
|
||
Here, the ref callback is first specified by `Grandparent`. It is passed to the `Parent` as a regular prop called `inputRef`, and the `Parent` passes it to the `CustomTextInput` as a prop too. Finally, the `CustomTextInput` reads the `inputRef` prop and attaches the passed function as a `ref` attribute to the `<input>`. As a result, `this.inputElement` in `Grandparent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`. | ||
Here, the ref `this.inputElement` is first specified by `Grandparent`. It is passed to the `Parent` as a regular prop called `inputRef`, and the `Parent` passes it to the `CustomTextInput` as a prop too. Finally, the `CustomTextInput` reads the `inputRef` prop and attaches the passed ref as a `ref` attribute to the `<input>`. As a result, `this.inputElement.value` in `Grandparent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`. | ||
|
||
All things considered, we advise against exposing DOM nodes whenever possible, but this can be a useful escape hatch. Note that this approach requires you to add some code to the child component. If you have absolutely no control over the child component implementation, your last option is to use [`findDOMNode()`](/docs/react-dom.html#finddomnode), but it is discouraged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All things considered, we advise against exposing DOM nodes whenever possible, but this can be a useful escape hatch.
Unrelated to this diff wording nit:
When possible, we advise against exposing DOM nodes, but it can be a useful escape hatch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
content/docs/refs-and-the-dom.md
Outdated
|
||
All things considered, we advise against exposing DOM nodes whenever possible, but this can be a useful escape hatch. Note that this approach requires you to add some code to the child component. If you have absolutely no control over the child component implementation, your last option is to use [`findDOMNode()`](/docs/react-dom.html#finddomnode), but it is discouraged. | ||
|
||
### Callback Refs | ||
|
||
React also supports another way to set refs called "callback refs", which give more fine-grain control over when refs are set and unset. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammar nit: "which give" should be "which gives" (b'c of "another way")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
content/docs/refs-and-the-dom.md
Outdated
<div> | ||
<input | ||
type="text" | ||
ref={(input) => { this.textInput = input; }} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think this, by the way. I don't think it's really a performance concern, but I think there's a tiny chance of confusion here. React will unset the old ref and re-set the new ref each render cycle, which I have known to confuse people in the past.
We even mention this as a caveat below. 😄
content/docs/refs-and-the-dom.md
Outdated
``` | ||
|
||
In the example above, `Parent` passes its ref callback as an `inputRef` prop to the `CustomTextInput`, and the `CustomTextInput` passes the same function as a special `ref` attribute to the `<input>`. As a result, `this.inputElement` in `Parent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`. | ||
|
||
### 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 as `this.refs.textInput`. We advise against it because string refs have [some issues](https://github.com/facebook/react/pull/8333#issuecomment-271648615), 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated to this diff: I wonder if we shouldn't make that last sentence stand out more by making it a bolded note:
Note
If you're currently using
this.refs.textInput
to access refs, we recommend the callback pattern instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the callback example more similar to the new API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates, Alex.
There's still one file with invalid line highlights, but otherwise I'd say this looks fine to go.
I am going to just edit this file directly.
content/docs/refs-and-the-dom.md
Outdated
|
||
```javascript{3,9} | ||
```javascript{4,7,12} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I merged this PR into the 16.3 docs PR since they need to go out at the same time anyway (see bvaughn/pull/1). |
Co-authored-by: QiChang Li <[email protected]>
This PR adds the new
React.createRef()
documentation to the refs page in the documentation.