I was going through React ⚛ lately and recently I figured this thing about writing inputs who's mere logic in React was quite intimidating 😨 for me as I was coming from just HTML background and things were quite simple there, isn't it? 🤷♂️ This was the same question in my mind couple of days ago and in the midst of writing a post on CSS (which is upcoming next!), I pulled off some time to explain this simple but frightening at first process of React. 🥳
🧩 Why these concepts, at all?
I am sure, you might be thinking instead of just writing good-looking and semantic HTML like below, why shall we need to have these concepts, in the first place. 🙄
<label>
<input type="text"> I 😍 HTML
</label>
Earlier when we had the vanilla JS way of doing things as we used to select the classname of input element above and do our plain old job of getting its value from the target property inside event.
But about time we see how much important forms are for websites and almost every other website today has a call-to-action form intact so we needed to assert more power over the form inputs. 💪
🙋♂️ So how do I write a form in React?
As you might have seen, React has this feeling of having all HTML inside its body and it respects the writing language of the web 🕸 so it gives us two ways in which we can build forms, one the conventional way known as 🚩 Uncontrolled Inputs, other the powerful one called 🚩 Controlled Inputs.
👩💻 ProTip: You can understand with utmost clarity if you open your React dev tools ⚙ along side writing this code, so you can always refer them to know what current state is.
🍕 Uncontrolled Inputs
Grab a slice of pizza, coz it's gonna be over before you finish yours.
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 above code snippet, refer below.
class Box extends React.Component {
render() {
return (
<label>
<input type="text" /> I 😍 HTML
</label>
);
}
}
But there's one catch. How to access the input? React gave us a dope way of doing that too! 🥳
😎 Introducing Refs
Refs provide a way to access DOM nodes or React elements created in the render method.
So ref
is nothing but an attribute like we had in HTML and it also 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>
)
}
}
- First things first, to be able to use
Ref
in your input you need to first initialize ref method in your class, by just callingReact.createRef()
. We named itfluffy
here. 😺 We'll mention that inside ourref
attribute inside input tag, like above. - Then comes our evergreen method,
onChange
which is required whenever there is some kind of change. - And lastly, inside
letsChange
which is called when there is some changes in input, we get the input value bythis.fluffly.current.value
. This gives us the text user typed, we can choose to use it however we want.
And this is all about, Uncontrolled Inputs. Did you finish your pizza, yet? 😏
⚡ Controlled Inputs
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 first place, because we are controlling its state ourselves. We need to store it's 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 now. 🙌
class Box extends React.Component {
state = { fluffy: "" }
letsChange = (event) => {
this.setState({
fluffy: event.target.value
})
}
render() {
return (
<label>
<input type="text" value={this.state.fluffy} onChange={this.letsChange} />
</label>
)
}
}
Yes, we're now unstoppable. 🤙 Now let's understand the flow of the above process.
- As mentioned earlier, we store the text in our state itself, so we create a
state
object and store an empty key namedfluffy
which will store the user input as he types. - Now what about change? So we pass a
onChange
attribute to input which callsletsChange
. This is the callback which occurs first when user makes the tiniest of changes. - Inside
letsChange
we are passing our all-time favourite argumentevent
which is used to set the state so that we can see it on the screen. - It's time to render what we stored in
fluffy
to the screen, so we create avalue
attribute in input tag as per HTML guidelines and store thefluffy
value inside it.
Hence, this above process takes place everytime any change is made by the user, by mutating the state object. 🐨
🍟 Benifits of using Controlled Inputs
This method gives us enourmous 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 nothing get input! Why is that? 😲
It is such, coz 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 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'll not be able to input any numbers in the input, coz the letsChange
function replaces them with empty strings ""
as soon you type something. You can also have a button which can be activated only if some specific conditions are satisfied. The possibilites 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 user to choose from and this is how we write that.
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 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 the default item selected will be that flower. You can manipulate the selection from 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. 💙
📚 Further Reading
Instead of conclusion, I thought to give y'all some resources that I found helpful during writing this post, I'm sure they'll help you some way or the other. 🚀
- Forms (React Docs)
- Uncontrolled Components (React Docs)
- Refs and the DOM (React Docs)
- The file input Tag (React Docs)
Top comments (4)
If you're interested, I recently showed an example of how you can use a controlled component, but avoid the hassle of having to manually write the
letsChange()
function:dev.to/bytebodger/decluttering-rea...
Thanks, Adam ❤ I will sure give that a read.
good explanation of controlled and unControlled input
Good to see you are doing such detailed research on these little things which are actually important conceptually.Want to see you grow more in this field.