How to Use React.findDOMNode in TypeScript
Aug 10, 2020 • 6 Minute Read
Introduction
Any web app involves extensive use of forms, and working with forms requires you to read DOM values, such as from an input field. These values can either be stored in the state, validated on the frontend, or sent to the server. In such situations, React allows you to use a method called React.findDOMNode(), which returns a native browser DOM element. However, using it in TypeScript requires some additional changes to the standard code.
This guide will show you how to correctly use React.findDOMNode() in a React and TypeScript app to extract values from a DOM element.
Setting up the React Typescript App
Create an empty TypeScript project in React by running the following command:
npx create-react-app react-dom-ts --typescript
Then create a simple Form component called Form.tsx.
import React from 'react';
export class Form extends React.Component<{},{}> {
render() {
return <h1>Inside Form Comp</h1>;
}
}
The above component simply renders some text. Add the interface for state and props and pass them to the class declaration of the form component. The state contains a single property name of type string .
import React from 'react';
interface State{
name:String
}
interface Props{
}
export class Form extends React.Component<Props,State> {
render() {
return <h1>Inside Form Comp</h1>;
}
}
Initialize the state inside the constructor.
constructor(props: Props){
super(props);
this.state={
name:''
}
}
So far, your form component's boilerplate is ready.
Creating the Form Template
Now that boilerplate is ready, next add a form inside the render() method of the form component that contains an input field and a submit button. To get a reference to the input, assign a ref attribute to the field as demonstrated below.
render() {
return
<form className="commentForm">
<input type="text" placeholder="Your name" ref="name" />
<button type="submit" >Submit</button>
{this.state.name}
</form>;
}
Also, add an onSubmit event to the form to listen to submit events on the form.
...
return <form className="commentForm" onSubmit={ e => this.handleSubmit(e) }>
...
Now all DOM manipulations can be done inside the handleSubmit() method. This method takes the event object as a parameter of type React.FormEvent. Call the e.preventDefault() method to prevent the default submit action of reloading the page.
handleSubmit(e: React.FormEvent) {
e.preventDefault();
}
Using React.findDOMNode() in TypeScript
To get the input DOM element, use the ReactDOM.findDOMNode() method by passing in the reference object of the DOM element as a parameter. In class components, your references can be accessed by calling this.refs and passing the name of the ref in square brackets. You can relate this to accessing a key in an object using bracket notation. Consider the following line of code:
let input = ReactDOM.findDOMNode(this.refs["name"])
ReactDOM.findDOMNode() returns the entire input element and stores it inside input, which is a local variable. If you were to write the above line of code in JavaScript, everything would work as intended. However, in TypeScript, you must also specify the type of element requested. Since it returns a DOM node of type HTMLInputElement, you must specify it using the as keyword. Hence the above line of code becomes
let input = ReactDOM.findDOMNode(this.refs["name"]) as HTMLInputElement;
Now the input variable stores the entire input DOM node. To get the value entered in this field, call the value property on this element and store it inside the state.
handleSubmit(e: React.FormEvent) {
e.preventDefault();
let input = ReactDOM.findDOMNode(this.refs["name"]) as HTMLInputElement;
console.log(input.value)
this.setState({
name:input.value
})
}
Final Code
Let's combine all the above code snippets. See the final code below.
import React from 'react';
import * as ReactDOM from 'react-dom'
interface State{
name:String
}
interface Props{
}
export class Form extends React.Component<Props, State> {
constructor(props: Props){
super(props);
this.state={
name:''
}
}
handleSubmit(e: React.FormEvent) {
e.preventDefault();
let input = ReactDOM.findDOMNode(this.refs["name"]) as HTMLInputElement;
console.log(input.value)
this.setState({
name:input.value
})
}
render() {
return <form className="commentForm" onSubmit={ e => this.handleSubmit(e) }>
<input type="text" placeholder="Your name" ref="name" />
<button type="submit" >Submit</button>
{this.state.name}
</form>;
}
}
Finally, remember to render your Form component inside App.tsx
import React from 'react';
import './App.css';
import { Form } from './Home';
function App() {
return (
<div className="App">
<Form/>
</div>
);
}
export default App;
If you type anything inside the input field and click the submit button, you will see the value of the field logged out on the console as well as on the page. This validates that you successfully captured the input field's value using React.findDOMNode() and stored it inside your component's state.
Conclusion
Simply attaching a ref callback to a particular DOM node should get you through all your required DOM manipulations smoothly. findDOMNode is more of a trick that you can use to access DOM elements. If you call it on a component that isn't created or mounted on the DOM yet, or a functional component, an exception will be thrown. React's official documentationclearly says to avoid using it since abstracts away from React's component architecture. A practical situation where you can use it is when your target ref is a component itself.