You still remember this comic from last post, right? I hope it's left a lasting impression on you since it's a really useful metaphor for thinking about React.
In this post, we're going to dive deeper into this topic. We'll focus on a different tag, <input>
, to complete our mental model.
input
Let's look at this component:
function App() {
return (
<div>
<input type="text" />
</div>
)
}
It's going to render a text box in the browser. Compared to the div
or span
we used before, input
is special since it's interactive -- it allows a user to change its content.
Let me ask you three questions.
First we add a button. When the button is clicked, we want to show an alert that contains the text in the text box.
function App() {
return (
<div>
<input type="text" />
<button onClick={
function() {
// TODO alert(text in the input)
}
}>Send</button>
</div>
)
}
How would we get the text that a user would enter into this text box?
If you are wondering how to get the reference of that input, THINK AGAIN! 1
Remember, always look at the data!
Right now, we only have a static structure in the component. There's no {}
at all. We need to add the data and cut a hole somewhere:
function App() {
const [draft, setDraft] = React.useState("")
return (
<div>
<input type="text" value={draft} />
<button onClick={
function() {
// TODO alert(text in the input)
}
}>Send</button>
</div>
)
}
So, how would we get the text of the text box? We should look at the value of draft
:
<button onClick={
function() {
alert(draft)
}
}>Send</button>
In fact, "what's the text in the text box" is almost the wrong question. What we should ask is "what's behind the hole", or "what's the data that's bound to the text box".
From this example, we also see that we can cut holes in an attribute's value, in addition to the content of a tag. But that's it. There are no other places where we could cut holes.
<input value={text} /> // โ
Correct
<div>๐ช{who}๐</div> // โ
Correct
<span>๐ช{who}{action}</span> // โ
Correct
<input {attr}="1" /> // โ Wrong
<{tagName} /> // โ Wrong
Let's use a different button. How would we change the text in the text box when the user clicks the button?
function App() {
const [draft, setDraft] = React.useState('')
return (
<div>
<input type="text" value={draft} />
<button
onClick={function () {
//TODO set the content of the textbox to "๐"
}}
>
๐
</button>
</div>
)
}
Again, if you want to do something like below, wrong answer.
$('input').val('๐')
Remember, always look at the data!
Since the input is bound to draft
via value={draft}
, we just need to change the data, and the text box will update itself:
setDraft('๐')
So the result would be like this:
The emoji buttons above work fine. However, if you try to type in the text box, you'll see that it doesn't work at all! Try it above.
Why?
Let's check out the code again:
function App() {
const [draft, setDraft] = React.useState("")
return (
<div>
<input type="text" value={draft} />
<button onClick={
function() {
setDraft("๐")
}
}>๐</button>
</div>
)
}
You see, the value of the input is determined by who's behind the hole, i.e. the value of draft
. The only way to change draft
is by calling setDraft
. The only moment we call setDraft
is when the button is clicked. It doesn't cover the situation when a user types in the text box!
To make the input work, we need to call setDraft
when a user types something into the text box:
<input type="text" value={draft}
onChange={
function(event) {
setDraft(event.target.value)
}
}/>
Here, event.target.value
is whatever the user types in the text box.
We've looked at <input>
as another example,
setXXX
function. In the input
, if it's bound to some data, we need to explicitly call setXXX
in onChange
. Otherwise a user won't be able to type in anything.When the input
has its value bound to a data item, i.e. the state, we call it a controlled component. We have similiar stories for other interactive HTML elements, such as select
and textarea
.
You might ask, are there uncontrolled components? You guess it right. I'll cover more about controlled and uncontrolled components in a future post.
But let's do some work out first! ๐
How about doing some Kung Fu routines with Panda? Try the slider and button below:
{ fontSize: 40 }
in the starter project? (Hint: it's a JavaScript thing.){}
around fontSize: 40
?fontSize
, how would you make it dynamic?event.target.value
, you'll need to use event.target.valueAsNumber
. Otherwise the code won't work.Got stuck? Here's the solution. Promise me, don't peek until you've tried your very best!
I hope you find this article useful!
One of my 2021 goals is to write more posts that are useful, interactive and entertaining. Want to receive early previews of future posts? Sign up below. No spam, unsubscribe anytime.