You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/docs/refs-and-the-dom.md
+167-40
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,8 @@ redirect_from:
11
11
permalink: docs/refs-and-the-dom.html
12
12
---
13
13
14
+
Refs provide a way to access DOM nodes or React elements created in the render method.
15
+
14
16
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.
15
17
16
18
### When to Use Refs
@@ -29,32 +31,69 @@ For example, instead of exposing `open()` and `close()` methods on a `Dialog` co
29
31
30
32
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.
31
33
32
-
### Adding a Ref to a DOM Element
34
+
> Note
35
+
>
36
+
> 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.
37
+
38
+
### Creating Refs
39
+
40
+
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.
41
+
42
+
```javascript{4,7}
43
+
class MyComponent extends React.Component {
44
+
constructor(props) {
45
+
super(props);
46
+
this.myRef = React.createRef();
47
+
}
48
+
render() {
49
+
return <div ref={this.myRef} />;
50
+
}
51
+
}
52
+
```
53
+
54
+
### Accessing Refs
55
+
56
+
When a ref is passed to an element in `render`, a reference to the node becomes accessible at the `value` attribute of the ref.
33
57
34
-
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.
58
+
```javascript
59
+
constnode=this.myRef.value
60
+
```
61
+
62
+
The value of the ref differs depending on the type of the node:
63
+
64
+
- 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.
65
+
- When the `ref` attribute is used on a custom class component, the `ref` object receives the mounted instance of the component as its `value`.
66
+
-**You may not use the `ref` attribute on functional components** because they don't have instances.
67
+
68
+
The examples below demonstrate the differences.
35
69
36
-
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:
70
+
#### Adding a Ref to a DOM Element
37
71
38
-
```javascript{8,9,19}
72
+
This code uses a `ref` to store a reference to a DOM node:
73
+
74
+
```javascript{5,12,22}
39
75
class CustomTextInput extends React.Component {
40
76
constructor(props) {
41
77
super(props);
78
+
// create a ref to store the textInput DOM element
// Explicitly focus the text input using the raw DOM API
47
-
this.textInput.focus();
85
+
// Note: we're accessing "value" to get the DOM node
86
+
this.textInput.value.focus();
48
87
}
49
88
50
89
render() {
51
-
// Use the `ref` callback to store a reference to the text input DOM
52
-
// element in an instance field (for example, this.textInput).
90
+
// tell React that we want the associate the <input> ref
91
+
// with the `textInput` that we created in the constructor
53
92
return (
54
93
<div>
55
94
<input
56
95
type="text"
57
-
ref={(input) => { this.textInput = input; }} />
96
+
ref={this.textInput} />
58
97
<input
59
98
type="button"
60
99
value="Focus the text input"
@@ -66,24 +105,26 @@ class CustomTextInput extends React.Component {
66
105
}
67
106
```
68
107
69
-
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.
70
-
71
-
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}`.
108
+
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.
72
109
73
-
### Adding a Ref to a Class Component
110
+
####Adding a Ref to a Class Component
74
111
75
-
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:
112
+
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:
76
113
77
-
```javascript{3,9}
114
+
```javascript{4,8,13}
78
115
class AutoFocusTextInput extends React.Component {
116
+
constructor(props) {
117
+
super(props);
118
+
this.textInput = React.createRef();
119
+
}
120
+
79
121
componentDidMount() {
80
-
this.textInput.focusTextInput();
122
+
this.textInput.value.focusTextInput();
81
123
}
82
124
83
125
render() {
84
126
return (
85
-
<CustomTextInput
86
-
ref={(input) => { this.textInput = input; }} />
127
+
<CustomTextInput ref={this.textInput} />
87
128
);
88
129
}
89
130
}
@@ -97,21 +138,24 @@ class CustomTextInput extends React.Component {
97
138
}
98
139
```
99
140
100
-
### Refs and Functional Components
141
+
####Refs and Functional Components
101
142
102
143
**You may not use the `ref` attribute on functional components** because they don't have instances:
103
144
104
-
```javascript{1,7}
145
+
```javascript{1,8,13}
105
146
function MyFunctionalComponent() {
106
147
return <input />;
107
148
}
108
149
109
150
class Parent extends React.Component {
151
+
constructor(props) {
152
+
super(props);
153
+
this.textInput = React.createRef();
154
+
}
110
155
render() {
111
156
// This will *not* work!
112
157
return (
113
-
<MyFunctionalComponent
114
-
ref={(input) => { this.textInput = input; }} />
158
+
<MyFunctionalComponent ref={this.textInput} />
115
159
);
116
160
}
117
161
}
@@ -123,25 +167,25 @@ You can, however, **use the `ref` attribute inside a functional component** as l
123
167
124
168
```javascript{2,3,6,13}
125
169
function CustomTextInput(props) {
126
-
// textInput must be declared here so the ref callback can refer to it
127
-
let textInput = null;
170
+
// textInput must be declared here so the ref can refer to it
171
+
let textInput = React.createRef();
128
172
129
173
function handleClick() {
130
-
textInput.focus();
174
+
textInput.value.focus();
131
175
}
132
176
133
177
return (
134
178
<div>
135
179
<input
136
180
type="text"
137
-
ref={(input) => { textInput = input; }} />
181
+
ref={textInput} />
138
182
<input
139
183
type="button"
140
184
value="Focus the text input"
141
185
onClick={handleClick}
142
186
/>
143
187
</div>
144
-
);
188
+
);
145
189
}
146
190
```
147
191
@@ -151,11 +195,11 @@ In rare cases, you might want to have access to a child's DOM node from a parent
151
195
152
196
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.
153
197
154
-
Instead, in such cases we recommend exposing a special prop on the child. The child would take a function 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 callback to the child's DOM node through the component in the middle.
198
+
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.
155
199
156
200
This works both for classes and for functional components.
157
201
158
-
```javascript{4,13}
202
+
```javascript{4,12,16}
159
203
function CustomTextInput(props) {
160
204
return (
161
205
<div>
@@ -165,25 +209,27 @@ function CustomTextInput(props) {
165
209
}
166
210
167
211
class Parent extends React.Component {
212
+
constructor(props) {
213
+
super(props);
214
+
this.inputElement = React.createRef();
215
+
}
168
216
render() {
169
217
return (
170
-
<CustomTextInput
171
-
inputRef={el => this.inputElement = el}
172
-
/>
218
+
<CustomTextInput inputRef={this.inputElement} />
173
219
);
174
220
}
175
221
}
176
222
```
177
223
178
-
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`.
224
+
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 `<input>`. As a result, `this.inputElement.value` in `Parent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`.
179
225
180
226
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 `<input>` itself is important, as it tells React to attach a ref to its DOM node.
181
227
182
228
This works even though `CustomTextInput` is a functional component. Unlike the special `ref` attribute which can [only be specified for DOM elements and for class components](#refs-and-functional-components), there are no restrictions on regular component props like `inputRef`.
183
229
184
230
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`:
185
231
186
-
```javascript{4,12,22}
232
+
```javascript{4,12,20,24}
187
233
function CustomTextInput(props) {
188
234
return (
189
235
<div>
@@ -200,26 +246,107 @@ function Parent(props) {
200
246
);
201
247
}
202
248
203
-
204
249
class Grandparent extends React.Component {
250
+
constructor(props) {
251
+
super(props);
252
+
this.inputElement = React.createRef();
253
+
}
254
+
render() {
255
+
return (
256
+
<Parent inputRef={this.inputElement} />
257
+
);
258
+
}
259
+
}
260
+
```
261
+
262
+
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`.
263
+
264
+
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.
265
+
266
+
### Callback Refs
267
+
268
+
React also supports another way to set refs called "callback refs", which gives more fine-grain control over when refs are set and unset.
269
+
270
+
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.
271
+
272
+
The example below implements a common pattern: using the `ref` callback to store a reference to a DOM node in an instance property.
273
+
274
+
```javascript{5,7-9,11-14,19,29,34}
275
+
class CustomTextInput extends React.Component {
276
+
constructor(props) {
277
+
super(props);
278
+
279
+
this.textInput = { value: null }; // initial placeholder for the ref
280
+
281
+
this.setTextInputRef = element => {
282
+
this.textInput.value = element
283
+
};
284
+
285
+
this.focusTextInput = () => {
286
+
// Focus the text input using the raw DOM API
287
+
this.textInput.value.focus();
288
+
};
289
+
}
290
+
291
+
componentDidMount () {
292
+
// autofocus the input on mount
293
+
if (this.textInput.value) this.focusTextInput()
294
+
}
295
+
205
296
render() {
297
+
// Use the `ref` callback to store a reference to the text input DOM
298
+
// element in an instance field (for example, this.textInput).
206
299
return (
207
-
<Parent
300
+
<div>
301
+
<input
302
+
type="text"
303
+
ref={this.setTextInputRef}
304
+
/>
305
+
<input
306
+
type="button"
307
+
value="Focus the text input"
308
+
onClick={this.focusTextInput}
309
+
/>
310
+
</div>
311
+
);
312
+
}
313
+
}
314
+
```
315
+
316
+
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.
317
+
318
+
You can pass callback refs between components like you can with object refs that were created with `React.createRef()`.
319
+
320
+
```javascript{4,13}
321
+
function CustomTextInput(props) {
322
+
return (
323
+
<div>
324
+
<input ref={props.inputRef} />
325
+
</div>
326
+
);
327
+
}
328
+
329
+
class Parent extends React.Component {
330
+
render() {
331
+
return (
332
+
<CustomTextInput
208
333
inputRef={el => this.inputElement = el}
209
334
/>
210
335
);
211
336
}
212
337
}
213
338
```
214
339
215
-
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`.
216
-
217
-
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.
340
+
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`.
218
341
219
342
### Legacy API: String Refs
220
343
221
-
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.
344
+
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**.
345
+
346
+
> Note
347
+
>
348
+
> If you're currently using `this.refs.textInput` to access refs, we recommend the callback pattern instead.
222
349
223
-
### Caveats
350
+
### Caveats with callback refs
224
351
225
352
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.
0 commit comments