React, forms and DOM nodes
To validate a form with the HTML5 constraint validation API you need to call .checkValidity()
on an actual <form>
DOM node. With a custom React form component, how would you access the constraint validation API inside a parent component?
ref and innerRef
Suppose we’ve got a component named App
that renders a custom form component named Form
, and we want to validate the form data from inside App
, using the constraint validation API.
Let’s define a new prop for our Form
component and let’s call the prop innerRef
. innerRef
should be a function. Form
passes the innerRef
prop as the ref
prop to the <form>
element.
function Form({ validated, innerRef, children, ...otherProps }) {
return (
<form
noValidate
className={formClasses}
ref={innerRef}
{...otherProps}
>
{children}
</form>
);
}
ref
is special. When React mounts a component, React calls the ref
prop and gives it the component DOM node as an argument.
In App
’s render()
function, pass a function that stores the DOM element in this.form
:
class App extends React.Component {
render() {
return (
<Form
innerRef={el => (this.form = el)}
>
</Form>);
}
}
After React has mounted the Form
component, we can access the form DOM element anywhere in the parent component using this.form
. To validate the form, call .checkValidity
directly on this.form
:
class App extends React.Component {
isValid() {
return this.form.checkValidity();
}
}
Done! You can use the same technique anywhere you want to access DOM nodes inside a component from the outside.
Further Reading
I first came across the innerRef
idea in Styled Components, but other React libraries use the same naming convention. The React documentation also talks about this pattern.
To brush up on React fundamentals, have a look at React for Real.