React and refs, an eternal love story
As in our previous exercise, we want to get the DOM node for a form component to validate the form with the HTML constraint validation API.
Since React 16.3, we can store references to DOM nodes with React.createRef()
. Let’s repeat the exercise with the new API.
We have two components, Form
and its parent App
. We want to store the validation logic inside App
, but we need access to the <form>
DOM node inside the Form
component to use the constraint validation API.
React.createRef()
creates special objects that can store references to React element DOM nodes. We’ll create one of these objects in the App
component, then pass it down to the Form
component to grab a reference to the <form>
DOM node.
In the App
component, create an instance variable with React.createRef()
:
class App extends React.Component {
state = {
validated: false
};
formRef = React.createRef();
}
Now we can access formRef
inside the render()
function as this.formRef
.
Pass this.formRef
to the Form
component as the innerRef
prop:
class App extends React.Component {
render() {
return (
<Form
innerRef={this.formRef}
>
);
}
}
Just as before, the Form
component passes innerRef
to its inner form
element as a ref
prop:
function Form({ innerRef, children, ...otherProps }) {
return (
<form noValidate className={formClasses} ref={innerRef} {...otherProps}>
{children}
</form>
);
}
Once React mounts the Form
component, thanks to the magic of React.createRef()
, formRef.current
in App
will contain a reference to the <form>
element DOM node. Since formRef.current
is a <form>
DOM node, we can call .checkValidity()
to validate the form.
class App extends React.Component {
onSubmit() {
this.formRef.current.checkValidity()
}
}
React.createRef()
gives you an object that stores the DOM node automatically, so you don’t need to write a function to do that for you.
So many refs, so little time
To recap, since React 16.3, you can pass either a function or a value created with React.createRef()
as the ref
prop.
If you pass a function, React will call the function when the component mounts, with the DOM node as an argument, and you can store a reference to the DOM node to access it later.
If you pass an object you created with React.createRef()
, you’ll be able to access the DOM node through the current
property on that object. That means you have to store the return value of React.createRef()
before passing it as a ref
prop.
The function ref
prop is still more powerful, because React also calls the function when it unmounts the component (in that case, React calls the function with null
), so you can perform arbitrary logic on both unmounting and mounting.
Further Reading
Take a look at the RFC for the new ref API to learn more about the motivation behind it. To learn about React fundamentals, read React for Real, of course ;).