From c09a2849977ae341c830843ffbc2b5d7bcfeaa98 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Thu, 22 Feb 2018 16:11:54 +0000 Subject: [PATCH 01/16] Added React.createRef doc --- content/docs/refs-and-the-dom.md | 136 ++++++++++++++++++++++++------- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index ca8e52c9e..bbb5cb4d9 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -31,30 +31,37 @@ Your first inclination may be to use refs to "make things happen" in your app. I ### Adding a Ref to a DOM Element +>**Note:** +> +>The examples below have updated to use the new `React.createRef()` API, introduced in React 16.3. + + 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: ```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(); this.focusTextInput = this.focusTextInput.bind(this); } focusTextInput() { // Explicitly focus the text input using the raw DOM API - this.textInput.focus(); + this.textInput.value.focus(); } render() { - // 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 ref + // to the `textInput` that we created in the constructor return (
{ this.textInput = input; }} /> + ref={this.textInput} /> this.textInput = input}`. +React will assign the `value` property with the DOM element when the component mounts, and assign it back to `null` when it unmounts. `ref` updates happen before `componentDidMount` or `componentDidUpdate` lifecycle hooks. ### Adding a Ref to a Class Component -When the `ref` attribute is used on a custom component declared as a class, the `ref` callback receives the mounted instance of the component as its argument. For example, if we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting: +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`. For example, if we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting: ```javascript{3,9} class AutoFocusTextInput extends React.Component { + constructor(props) { + super(props); + this.textInput = React.createRef(); + } componentDidMount() { - this.textInput.focusTextInput(); + this.textInput.value.focusTextInput(); } render() { return ( - { this.textInput = input; }} /> + ); } } @@ -107,11 +115,14 @@ function MyFunctionalComponent() { } class Parent extends React.Component { + constructor(props) { + super(props); + this.textInput = React.createRef(); + } render() { // This will *not* work! return ( - { this.textInput = input; }} /> + ); } } @@ -123,18 +134,18 @@ You can, however, **use the `ref` attribute inside a functional component** as l ```javascript{2,3,6,13} function CustomTextInput(props) { - // textInput must be declared here so the ref callback can refer to it - let textInput = null; + // textInput must be declared here so the ref can refer to it + let textInput = React.createRef(); function handleClick() { - textInput.focus(); + textInput.value.focus(); } return (
{ textInput = input; }} /> + ref={textInput} /> this.inputElement = el} - /> + ); } } ``` -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 ``. As a result, `this.inputElement` in `Parent` will be set to the DOM node corresponding to the `` element in the `CustomTextInput`. +In the example above, `Parent` passes its class property `this.inputElement` as an `inputRef` prop to the `CustomTextInput`, and the `CustomTextInput` passes the same ref as a special `ref` attribute to the ``. As a result, `this.inputElement.value` in `Parent` will be set to the DOM node corresponding to the `` element in the `CustomTextInput`. Note that the name of the `inputRef` prop in the above example has no special meaning, as it is a regular component prop. However, using the `ref` attribute on the `` itself is important, as it tells React to attach a ref to its DOM node. @@ -202,24 +215,91 @@ function Parent(props) { class Grandparent extends React.Component { + constructor(props) { + super(props); + this.inputElement = React.createRef(); + } render() { return ( - this.inputElement = el} - /> + ); } } ``` -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 ``. As a result, `this.inputElement` in `Grandparent` will be set to the DOM node corresponding to the `` 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 ``. As a result, `this.inputElement.value` in `Grandparent` will be set to the DOM node corresponding to the `` 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. +### 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. + +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: + +```javascript{8,9,19} +class CustomTextInput extends React.Component { + constructor(props) { + super(props); + this.focusTextInput = this.focusTextInput.bind(this); + } + + focusTextInput() { + // Explicitly focus the text input using the raw DOM API + this.textInput.focus(); + } + + render() { + // Use the `ref` callback to store a reference to the text input DOM + // element in an instance field (for example, this.textInput). + return ( +
+ { this.textInput = input; }} /> + +
+ ); + } +} +``` + +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}`. + +You can pass callback refs between components like you can with object refs that were created with `React.createRef()`. + +```javascript{4,13} +function CustomTextInput(props) { + return ( +
+ +
+ ); +} + +class Parent extends React.Component { + render() { + return ( + this.inputElement = el} + /> + ); + } +} +``` + +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 ``. As a result, `this.inputElement` in `Parent` will be set to the DOM node corresponding to the `` 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. -### Caveats +### Caveats with callback refs If the `ref` callback is defined as an inline function, it will get called twice during updates, first with `null` and then again with the DOM element. This is because a new instance of the function is created with each render, so React needs to clear the old ref and set up the new one. You can avoid this by defining the `ref` callback as a bound method on the class, but note that it shouldn't matter in most cases. From ee783589390097acc1e0a0876b8b67460d6fb510 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Thu, 22 Feb 2018 20:54:52 +0000 Subject: [PATCH 02/16] address feedback --- content/docs/refs-and-the-dom.md | 42 +++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index bbb5cb4d9..b59a59073 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -36,11 +36,35 @@ Your first inclination may be to use refs to "make things happen" in your app. I >The examples below have updated to use the new `React.createRef()` API, introduced in React 16.3. -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. +Refs can be created using `React.createRef()` and are commonly assigned to a component class instance in the constructor or via a property initializer. + +```javascript{4} +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.myRef = React.createRef(); + } +} +``` + +Refs can then be attached to React elements via the `ref` attribute by passing the property on the class instance as the value to that attribute. + + +```javascript{4,7} +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.myRef = React.createRef(); + } + render() { + return
; + } +} +``` 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: -```javascript{8,9,19} +```javascript{5,11,21} class CustomTextInput extends React.Component { constructor(props) { super(props); @@ -56,7 +80,7 @@ class CustomTextInput extends React.Component { render() { // tell React that we want the associate the ref - // to the `textInput` that we created in the constructor + // with the `textInput` that we created in the constructor return (
; } @@ -166,7 +190,7 @@ Instead, in such cases we recommend exposing a special prop on the child. The ch This works both for classes and for functional components. -```javascript{4,13} +```javascript{4,12,16} function CustomTextInput(props) { return (
@@ -196,7 +220,7 @@ This works even though `CustomTextInput` is a functional component. Unlike the s Another benefit of this pattern is that it works several components deep. For example, imagine `Parent` didn't need that DOM node, but a component that rendered `Parent` (let's call it `Grandparent`) needed access to it. Then we could let the `Grandparent` specify the `inputRef` prop to the `Parent`, and let `Parent` "forward" it to the `CustomTextInput`: -```javascript{4,12,22} +```javascript{4,12,21,25} function CustomTextInput(props) { return (
@@ -233,9 +257,9 @@ All things considered, we advise against exposing DOM nodes whenever possible, b ### 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. +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. -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: +With callback refs, instead of creating a ref with `React.createRef()`, you 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: ```javascript{8,9,19} class CustomTextInput extends React.Component { From b049931a65db0316f31760d48a556b7848e0f2e5 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Sat, 3 Mar 2018 17:19:42 -0800 Subject: [PATCH 03/16] revised content as per PR feedback --- content/docs/refs-and-the-dom.md | 39 ++++++++++++-------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index b59a59073..e17e9c46f 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -33,22 +33,10 @@ Your first inclination may be to use refs to "make things happen" in your app. I >**Note:** > ->The examples below have updated to use the new `React.createRef()` API, introduced in React 16.3. +>The examples below have updated to use the `React.createRef()` API introduced in React 16.3. -Refs can be created using `React.createRef()` and are commonly assigned to a component class instance in the constructor or via a property initializer. - -```javascript{4} -class MyComponent extends React.Component { - constructor(props) { - super(props); - this.myRef = React.createRef(); - } -} -``` - -Refs can then be attached to React elements via the `ref` attribute by passing the property on the class instance as the value to that attribute. - +Refs can be created using `React.createRef()` and are commonly assigned to an instance property when a component is constructed. ```javascript{4,7} class MyComponent extends React.Component { @@ -62,9 +50,11 @@ class MyComponent extends React.Component { } ``` +Refs can then be attached to React elements via the `ref` attribute by passing the property on the class instance as the value to that attribute. + 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: -```javascript{5,11,21} +```javascript{5,12,22} class CustomTextInput extends React.Component { constructor(props) { super(props); @@ -75,6 +65,7 @@ class CustomTextInput extends React.Component { focusTextInput() { // Explicitly focus the text input using the raw DOM API + // Note: we're accessing "value" to get the DOM node this.textInput.value.focus(); } @@ -257,20 +248,18 @@ All things considered, we advise against exposing DOM nodes whenever possible, b ### 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. +React also supports another way to set refs called "callback refs", which give more fine-grain control over when refs are set and unset. -With callback refs, instead of creating a ref with `React.createRef()`, you 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: +Instead of passing a `ref` attribute created by `createRef()`, 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 the `ref` callback to store a reference to a DOM node: -```javascript{8,9,19} +```javascript{6,17} class CustomTextInput extends React.Component { constructor(props) { super(props); - this.focusTextInput = this.focusTextInput.bind(this); - } - - focusTextInput() { - // Explicitly focus the text input using the raw DOM API - this.textInput.focus(); + this.focusTextInput = () => { + // Explicitly focus the text input using the raw DOM API + this.textInput.focus(); + }; } render() { @@ -294,7 +283,7 @@ class CustomTextInput extends React.Component { 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}`. +Using the `ref` callback 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}`. You can pass callback refs between components like you can with object refs that were created with `React.createRef()`. From 9bc19326887ae85e6ce327203c2245d3028cec36 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Sat, 3 Mar 2018 17:25:02 -0800 Subject: [PATCH 04/16] updated line numbers --- content/docs/refs-and-the-dom.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index e17e9c46f..c23e24bad 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -94,12 +94,13 @@ React will assign the `value` property with the DOM element when the component m 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`. For example, if we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting: -```javascript{4,12} +```javascript{4,7,12} class AutoFocusTextInput extends React.Component { constructor(props) { super(props); this.textInput = React.createRef(); } + componentDidMount() { this.textInput.value.focusTextInput(); } @@ -124,7 +125,7 @@ class CustomTextInput extends React.Component { **You may not use the `ref` attribute on functional components** because they don't have instances: -```javascript{1,8,12} +```javascript{1,8,13} function MyFunctionalComponent() { return ; } @@ -167,7 +168,7 @@ function CustomTextInput(props) { onClick={handleClick} />
- ); + ); } ``` @@ -211,7 +212,7 @@ This works even though `CustomTextInput` is a functional component. Unlike the s Another benefit of this pattern is that it works several components deep. For example, imagine `Parent` didn't need that DOM node, but a component that rendered `Parent` (let's call it `Grandparent`) needed access to it. Then we could let the `Grandparent` specify the `inputRef` prop to the `Parent`, and let `Parent` "forward" it to the `CustomTextInput`: -```javascript{4,12,21,25} +```javascript{4,12,20,24} function CustomTextInput(props) { return (
@@ -228,7 +229,6 @@ function Parent(props) { ); } - class Grandparent extends React.Component { constructor(props) { super(props); From 6627687b0bb794c910b2189345b3e948e9d263d9 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 3 Mar 2018 18:05:41 -0800 Subject: [PATCH 05/16] Describe what a ref is at the top of the doc --- content/docs/refs-and-the-dom.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index c23e24bad..3a7f133b7 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -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. + In the typical React dataflow, [props](/docs/components-and-props.html) are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch. ### When to Use Refs From 0e7243f7fb1cc38bcfe87752ce62317fd9e0e0a4 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 3 Mar 2018 18:12:00 -0800 Subject: [PATCH 06/16] Merge intro paragraphs --- content/docs/refs-and-the-dom.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 3a7f133b7..e0ad61806 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -37,8 +37,7 @@ Your first inclination may be to use refs to "make things happen" in your app. I > >The examples below have updated to use the `React.createRef()` API introduced in React 16.3. - -Refs can be created using `React.createRef()` and are commonly assigned to an instance property when a component is constructed. +Refs can be created using `React.createRef()` and attached to React elements via the `ref` attribute. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the the component. ```javascript{4,7} class MyComponent extends React.Component { @@ -52,8 +51,6 @@ class MyComponent extends React.Component { } ``` -Refs can then be attached to React elements via the `ref` attribute by passing the property on the class instance as the value to that attribute. - 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: ```javascript{5,12,22} From 7b02740afe0f890e0d9ee39a1be4ac5f9cb7f0a0 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 3 Mar 2018 18:33:43 -0800 Subject: [PATCH 07/16] Create "Accessing refs" section above specific examples --- content/docs/refs-and-the-dom.md | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index e0ad61806..0fc033df0 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -31,13 +31,13 @@ For example, instead of exposing `open()` and `close()` methods on a `Dialog` co Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. See the [Lifting State Up](/docs/lifting-state-up.html) guide for examples of this. -### Adding a Ref to a DOM Element - >**Note:** > >The examples below have updated to use the `React.createRef()` API introduced in React 16.3. -Refs can be created using `React.createRef()` and attached to React elements via the `ref` attribute. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the the component. +### Creating Refs + +Refs are created using `React.createRef()` and attached to React elements via the `ref` attribute. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the the component. ```javascript{4,7} class MyComponent extends React.Component { @@ -51,7 +51,25 @@ class MyComponent extends React.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. For example, this code uses a `ref` to store a reference to a DOM node: +### 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. + +```javascript +const node = this.myRef.value +``` + +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`. +- **You may not use the `ref` attribute on functional components** because they don't have instances. + +The examples below demonstrate the differences. + +#### Adding a Ref to a DOM Element + +This code uses a `ref` to store a reference to a DOM node: ```javascript{5,12,22} class CustomTextInput extends React.Component { @@ -89,9 +107,9 @@ class CustomTextInput extends React.Component { React will assign the `value` property with the DOM element when the component mounts, and assign it back to `null` when it unmounts. `ref` updates happen before `componentDidMount` or `componentDidUpdate` lifecycle hooks. -### Adding a Ref to a Class Component +#### Adding a Ref to a Class Component -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`. For example, if we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting: +If we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting, we could use a ref to get access to the custom input and call its `focusTextInput` method manually: ```javascript{4,7,12} class AutoFocusTextInput extends React.Component { @@ -120,7 +138,7 @@ class CustomTextInput extends React.Component { } ``` -### Refs and Functional Components +#### Refs and Functional Components **You may not use the `ref` attribute on functional components** because they don't have instances: From 8075ce2db759a41af4d86a4dc96eac9fecc60a0f Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 3 Mar 2018 18:53:16 -0800 Subject: [PATCH 08/16] Make the callback example more similar to the new API --- content/docs/refs-and-the-dom.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 0fc033df0..d165c05a5 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -267,18 +267,25 @@ All things considered, we advise against exposing DOM nodes whenever possible, b 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 by `createRef()`, 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 the `ref` callback to store a reference to a DOM node: +Instead of passing a `ref` attribute created by `createRef()`, 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. + +The example below implements a common pattern: using the `ref` callback to store a reference to a DOM node in an instance property. ```javascript{6,17} class CustomTextInput extends React.Component { constructor(props) { super(props); + this.textInput = { value: null }; // initial placeholder for the ref this.focusTextInput = () => { - // Explicitly focus the text input using the raw DOM API - this.textInput.focus(); + // Focus the text input using the raw DOM API + this.textInput.value.focus(); }; } + componentDidMount () { + if (this.textInput) this.focusTextInput() // autofocus the input on mount + } + render() { // Use the `ref` callback to store a reference to the text input DOM // element in an instance field (for example, this.textInput). @@ -286,7 +293,7 @@ class CustomTextInput extends React.Component {
{ this.textInput = input; }} /> + ref={element => this.textInput.value = element} /> this.textInput = input}`. - You can pass callback refs between components like you can with object refs that were created with `React.createRef()`. ```javascript{4,13} From 96fe82c7347dfe9360dde7c3e6f5270b1fe57dcd Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 6 Mar 2018 00:43:56 -0800 Subject: [PATCH 09/16] Declare setRef method outside render --- content/docs/refs-and-the-dom.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index d165c05a5..30671b493 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -271,11 +271,17 @@ Instead of passing a `ref` attribute created by `createRef()`, you pass a functi The example below implements a common pattern: using the `ref` callback to store a reference to a DOM node in an instance property. -```javascript{6,17} +```javascript{5,7-9,11-14,19,29,34} class CustomTextInput extends React.Component { constructor(props) { super(props); + this.textInput = { value: null }; // initial placeholder for the ref + + this.setTextInputRef = element => { + this.textInput.value = element + }; + this.focusTextInput = () => { // Focus the text input using the raw DOM API this.textInput.value.focus(); @@ -283,7 +289,8 @@ class CustomTextInput extends React.Component { } componentDidMount () { - if (this.textInput) this.focusTextInput() // autofocus the input on mount + // autofocus the input on mount + if (this.textInput.value) this.focusTextInput() } render() { @@ -293,7 +300,8 @@ class CustomTextInput extends React.Component {
this.textInput.value = element} /> + ref={this.setTextInputRef} + /> Date: Tue, 6 Mar 2018 00:46:36 -0800 Subject: [PATCH 10/16] Grammar --- content/docs/refs-and-the-dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 30671b493..24aa80956 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -265,7 +265,7 @@ All things considered, we advise against exposing DOM nodes whenever possible, b ### 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. +React also supports another way to set refs called "callback refs", which gives more fine-grain control over when refs are set and unset. Instead of passing a `ref` attribute created by `createRef()`, 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. From 962ef9a56741e2621301208e4fe68138976bb944 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 6 Mar 2018 00:50:44 -0800 Subject: [PATCH 11/16] Highlight deprecation notice --- content/docs/refs-and-the-dom.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 0fc033df0..796f04ffd 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -328,7 +328,11 @@ In the example above, `Parent` passes its ref callback as an `inputRef` prop to ### 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. +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**. + +> Note +> +> If you're currently using `this.refs.textInput` to access refs, we recommend the callback pattern instead. ### Caveats with callback refs From 4b939d2448fc911a4c1542e5810bbc7dd91d1d23 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 6 Mar 2018 00:55:22 -0800 Subject: [PATCH 12/16] ~~All things considered~~ --- content/docs/refs-and-the-dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 796f04ffd..70c506a7e 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -261,7 +261,7 @@ class Grandparent extends React.Component { 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 ``. As a result, `this.inputElement.value` in `Grandparent` will be set to the DOM node corresponding to the `` 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. +When possible, we advise against exposing DOM nodes, but it 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 From 04c7f16ef254f4b49c0fcccbff203b355e1753ec Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 6 Mar 2018 00:56:26 -0800 Subject: [PATCH 13/16] Wording --- content/docs/refs-and-the-dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 70c506a7e..5af30cb1c 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -195,7 +195,7 @@ In rare cases, you might want to have access to a child's DOM node from a parent While you could [add a ref to the child component](#adding-a-ref-to-a-class-component), this is not an ideal solution, as you would only get a component instance rather than a DOM node. Additionally, this wouldn't work with functional components. -Instead, in such cases we recommend exposing a special prop on the child. The child would take a prop with an arbitrary name (e.g. `inputRef`) and attach it to the DOM node as a `ref` attribute. This lets the parent pass its ref to the child's DOM node through the component in the middle. +Instead, in such cases we recommend exposing a special prop on the child. This prop can be named anything other than ref (e.g. inputRef). The child component can then forward the prop to the DOM node as a ref attribute. This lets the parent pass its ref to the child's DOM node through the component in the middle. This works both for classes and for functional components. From b1adba0a38f73b0e01ffaaac8aa0eb5041ce98cd Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 6 Mar 2018 00:59:50 -0800 Subject: [PATCH 14/16] Recommend old API when applicable --- content/docs/refs-and-the-dom.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 5af30cb1c..26477b4b3 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -31,9 +31,9 @@ For example, instead of exposing `open()` and `close()` methods on a `Dialog` co Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. See the [Lifting State Up](/docs/lifting-state-up.html) guide for examples of this. ->**Note:** +> Note > ->The examples below have updated to use the `React.createRef()` API introduced in React 16.3. +> 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. ### Creating Refs @@ -59,10 +59,10 @@ When a ref is passed to an element in `render`, a reference to the node becomes const node = this.myRef.value ``` -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: +The value of the ref differs depending on the type of the 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. -- 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`. +- When the `ref` attribute is used on a custom class component, the `ref` object receives the mounted instance of the component as its `value`. - **You may not use the `ref` attribute on functional components** because they don't have instances. The examples below demonstrate the differences. From 9b869fa73f4148c53f6190c8197a1b0bbc83e203 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 6 Mar 2018 01:02:05 -0800 Subject: [PATCH 15/16] Update leading sentence --- content/docs/refs-and-the-dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index 26477b4b3..463ec637d 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -11,7 +11,7 @@ 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. +Refs provide a way to access DOM nodes or React elements created in the render method. In the typical React dataflow, [props](/docs/components-and-props.html) are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch. From f6e5d655ddc65999405a387d505c0f45877c9d07 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 7 Mar 2018 10:38:17 -0800 Subject: [PATCH 16/16] Fixed off-by-one line highlights. --- content/docs/refs-and-the-dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/refs-and-the-dom.md b/content/docs/refs-and-the-dom.md index f16790fa2..4d31a1054 100644 --- a/content/docs/refs-and-the-dom.md +++ b/content/docs/refs-and-the-dom.md @@ -111,7 +111,7 @@ React will assign the `value` property with the DOM element when the component m If we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting, we could use a ref to get access to the custom input and call its `focusTextInput` method manually: -```javascript{4,7,12} +```javascript{4,8,13} class AutoFocusTextInput extends React.Component { constructor(props) { super(props);