The onClick Parable
There's a mistake I've seen lots of React developers make. This lesson is a cautionary tale about it.
Let's suppose we're building a search form:
Code Playground
In this example, runSearch
is the function we want to call when the user clicks/taps the "Search!" button. In Module 3, we'll learn how to make network requests, but for now, it's a .
Here's the question: how should I use this function?
A lot of developers instinctively solve for this by adding an onClick
handler to the submit button:
<button onClick={() => runSearch(searchTerm)}> Search!</button>
There are a number of problems with this approach. For example, what if the user tries to search by pressing "Enter" after typing in the text input?
Well… I suppose we could tackle that with an onKeyDown
event listener?
<input type="text" value={searchTerm} onChange={event => { setSearchTerm(event.target.value); }} onKeyDown={event => { if (event.key === 'Enter') { runSearch(searchTerm); } }}/>
We're going down a bad road here. We're re-implementing stuff that the browser already knows how to do!
Use a form
To solve this problem, along with so many others, we should wrap our form controls in a <form>
tag.
Then, instead of listening for clicks and keys, we can listen for the form submit event.
Look how much simpler the code gets:
Code Playground
The form submit event will be called automatically when the user clicks the button, or presses "Enter" whenever the input or button is focused. When that event fires, we'll run our search.
Instead of trying to re-create a bunch of standard web platform stuff, we should use the platform and let it solve these sorts of problems for us!
By using a form submit event, we get to use client-side validation:
<input type="password" required={true} minLength={8}/>
Learn more about validation attributes like required
, minLength
, and pattern
on MDN.
Default form behavior
Alright, so there is one little quirk with using onSubmit
. We need to prevent the default submission behavior:
<form className="search-form" onSubmit={event => { event.preventDefault(); runSearch(searchTerm); }}>
To understand why this is necessary, we need to take a trip back through time, to an era without client-side requests. Before fetch
, before XMLHttpRequest
, before JSON.
If you wanted to make a request to a server, like when fetching search results, you couldn't request only the data. You needed to request a whole new HTML file. Essentially, the user would be redirected to a new URL, and the server would then render a template into an HTML document, using the data sent with the request.
Forms still operate this way by default. When you submit a form, the browser will try to send the user to the URL specified by the action
attribute:
<!-- Submitting this form will redirect the user to the /search page, sending along the data collected from the form fields.--><form method="POST" action="/search">
If we omit the action
attribute, the browser will use the current URL, effectively reloading the page.
In the context of a modern React application, this isn't usually what we want. We don't want to reload the entire page, we want to fetch a bit of data and re-render a few components with that data. This produces a faster, smoother user experience.
That's why we need to include event.preventDefault()
. It stops the browser from executing a full page reload.