I am sure you must be thinking, “Why would we need to have these concepts at all when we can just write good-looking, semantic HTML like below?”
When you follow the vanilla JS way of doing things, you select the class name of the input element above and do our job of getting its value from the target property inside the event.
However, it is good to know how important forms are for websites as, today, almost every website has a call-to-action form.
As you might have seen, React has all its HTML inside its body, and it respects the writing language of the web. Hence, it gives us two ways in which we can build forms, the conventional way is known as Uncontrolled Inputs, and the powerful way is called Controlled Inputs.
ProTip: It is easier to understand if you open your React dev tools alongside this code so that you can always refer to it to know what current state is.
This is where we get to keep the traditional way of writing HTML inputs and, guess what, it’s pretty much the same as the code snippet above (refer below):
class Box extends React.Component (
render() {
return (
<label>
<input type="text" /> I 😍 HTML
</label>
);
}
)
But there is one catch – how will we access the input? Don’t worry, React has given us a dope way of doing that too!
Refs provide a way to access DOM nodes or React elements created in the render method.
For more information, go to the React documentation
So, ref
is nothing but an attribute, like we have in HTML, and it provides a way for us to get access to the DOM so that we can get the user-typed data from the input. Let’s see how:
class Box extends React.Component {
fluffy = React.createRef()
letsChange = () => {
console.log(this.fluffy.current.value) // input value gets logged
}
render() {
return (
<label>
<input type="text" ref={this.fluffy} onChange={this.letsChange} />
I 😍 HTML
</label>
)
}
In the code below, click the output tab and enter your name in the input
tag. You can see the changes in the console tab.
import React from 'react'; import ReactDOM from 'react-dom'; import Box from './app.js'; ReactDOM.render( <Box />, document.getElementById('root') );
Ref
in your input, you need to first initialize the ref method in your class by calling React.createRef()
. We have named it fluffy
here. We’ll mention that inside our ref
attribute inside the input tag, like above.onChange
, which is required whenever there is some kind of change.letsChange
, which is called when there are some changes in input, we get the input value by this.fluffly.current.value
. This gives us the user-typed text that we can then choose to use however we want.This gives all the power to your plain old input forms. This is the de facto standard of creating forms in React. It’s called controlled in the first place because we are controlling its state ourselves. We need to store its value inside the state object and keep it updated in real-time as well as the user types. So, let’s get our hands dirty.
import React from 'react'; import ReactDOM from 'react-dom'; import Box from './app.js'; ReactDOM.render( <Box />, document.getElementById('root') );
We’re unstoppable! Now ,let’s understand the flow of the process above.
fluffy,
which will store the user input as they type.onChange
attribute to input that calls letsChange
. This is the callback that first occurs when the user makes the tiniest of changes.letsChange
we are passing our all-time favorite argument, event
, which is used to set the state so that we can see it on the screen.fluffy
to the screen, so we create a value
attribute in the input tag, as per HTML guidelines, and store the fluffy
value inside it.The above process takes place every time any change is made by the user by mutating the state object.
This method gives us enormous control over the state, which, in turn, gives us power over the input. To see this, you can remove or comment out the letsChange
function and try typing in the box. You’ll see that nothing gets input! Why is that?
The reason for this is that the input box directly renders the text stored inside state which comes through the letsChange
function. Hence, this system allows us to filter the values provided by the user before displaying it on the screen itself. Let’s say you want to do some sort of custom validation for the user data, you can easily put the code into the letsChange
function and see the magic.
// ...
letsChange = event => {
let input = event.target.value;
input = input.replace(/[0-9]/g, "");
this.setState({ fluffy: input });
};
// ...
You won’t be able to input any numbers in the input because the letsChange function replaces them with empty strings as soon as you type something. You can also have a button that can be activated only if specific conditions are satisfied. The possibilities are endless.
If that doesn’t make sense, let me give you another example of this type.
Let’s say we need a dropdown menu of various flowers for the user to choose from and we write it as:
class Multiple extends React.Component {
state = {
flower: "",
};
letsChange = event => {
this.setState({ flower: event.target.value });
};
render() {
return (
<label>
Your Favourite Flower: 🌸
<select value={this.state.flower} onChange={this.letsChange}>
<option value="rose">Rose 🌹</option>
<option value="sunflower">Sunflower 🌻</option>
<option value="tulip">Tulip 🌷</option>
<option value="hibiscus">Hibiscus 🌺</option>
</select>
</label>
);
}
}
In the above example, if you try putting any of the four values that we gave in option in place of flower
inside state, then you’ll see that the default item selected will be that flower. You can manipulate the selection from the letsChange
function as well.
P.S.: There’s this file input tag whose value is only read-only, so it is by default an uncontrolled component in React. Further reading on this is mentioned below. Rest assured, you’re good to go.
Free Resources