
You should be familiar with events if you've ever manipulated JavaScript. There's no harm in a quick reminder, though! An event is aĀ reactionĀ to anĀ actionĀ carried out by the user, such as clicking a button or entering text in a form.Ā Ā Ā
Some good news: with its practical and concise syntax, React makes managing events in the DOM much easier. š
When declaring an event in React, there are a few things to remember:
Events are written within a tag inĀ camelCase.
You declare the event to be captured, passing it the function to be called written between curly braces.Ā
Unlike in JS, youāll almost never have to use Ā addEventListener.
Letās try that out in our code. In Ā components/PlantItem.jsĀ , declare a Ā handleClick, which will make a log on our console:
function handleClick() {
console.log('⨠This is a click āØ')
}Now addĀ Ā onClick={handleClick}Ā in the Ā liĀ tag of the Ā PlantItemĀ component, giving us:Ā
<li className='jh-plant-item' onClick={handleClick}>
<img className='jh-plant-item-cover' src={cover} alt={`${name} cover`} />
{name}
<div>
<CareScale careType='water' scaleValue={water} />
<CareScale careType='light' scaleValue={light} />
</div>
</li>Open the console and⦠Yay! Itās worked! š„³
Letās take this exercise a bit further by triggering an alert that displays the name of the plant that has been clicked on.
Pass Ā plantNameĀ as a parameter of Ā handleClickĀ like this:
function handleClick(plantName) {
alert(`You want to buy 1 ${plantName}? Great choice š±āØ`)
}But if I click on it, it doesnāt work:
![The message reads, localhost:3000 says You want to buy 1 [object Object]? Great choice, followed by a plant emoji and a sparkle emoji.](https://user.oc-static.com/upload/2021/05/06/16202856603469_2c5image1.png)
React passes an object by default (weāll deal with this in a few minutes), but here you want to specify your argument.
Itās easy to do this: declare a function directly in Ā onClickĀ (arrow functions are handy for doing this). This function will call handleClick, passing Ā nameĀ as a parameter:
onClick={() => handleClick(name)}That shouldĀ work perfectly! š
Let's see what it looks like when React passes the default object as a parameter to the functions indicated in the event callback:
If youĀ pull the parameter in handleClick:Ā
function handleClick(e) {
console.log('⨠This is my event :', e)
}And then call it without passing the name:
onClick={handleClick}Give it a go for yourself!
It looks like thereās a lot of information there ā how does it all relate? š¤
It is whatās known as a synthetic event. Itās the same interface as for native events in the DOM, except that these are compatible with all browsers.Ā
Practical, isnāt it?
Given that itās the same interface as for native events in the DOM, do we also have access to Ā preventDefaultĀ and Ā stopPropagationĀ ?Ā
Absolutely! You can use these methods with the parameter pulled from the function passed to the event. In our case, you could have used Ā e.preventDefault()Ā . If you need a refresher onĀ Ā preventDefaultĀ and Ā stopPropagationĀ , readĀ this chapter on listening for events inĀ the course,Ā Write JavaScript for the Web.Ā
React simplifies form management: you can easily access the value, whether it's an input checkbox, textarea, or even a select with Ā onChangeĀ .
There are two main ways to manage forms: controlled and uncontrolled. You should deal with the uncontrolled method swiftly because it requires less involvement from React, which encourages the use of controlled forms.Ā Ā
Let's look at a demonstration of an uncontrolled form. We're going to put a Ā QuestionFormĀ component directly in our app'sĀ App.jsĀ .Ā Then we'll declare it in a separate file and add a field for a question.
Here's aĀ form that wrapsĀ our input:
<form onSubmit={handleSubmit}>
<input type='text' name='my_input' defaultValue='Type your text' />
<button type='submit'>Enter</button>
</form>And for Ā handleSubmit, we get:
function handleSubmit(e) {
e.preventDefault()
alert(e.target['my_input'].value)
}Youāll see that React allows us to specify a Ā defaultValueĀ in the input field.Ā Let's call Ā preventDefaultĀ ; otherwise,Ā Ā submitĀ will refresh the page.Ā
OurĀ alert is triggered. š„³
Pretty simple, isnāt it? Youāre delegating the work to your DOM. Indeed, uncontrolled forms mean you don't have to manage too much information. However, this approach is a bit less React, because it has its limitations.Ā Ā
Instead,Ā consider using controlled components.
Local stateĀ allows you toĀ hold specific component information and comes from an interactionĀ that the user has had with a component.Ā Ā
Let's create an inputValueĀ variable and the function that we'll use to change its value in the local state with Ā useStateĀ .Ā Ā
The line of code below allowsĀ us to set the initial state for Ā inputValueĀ andĀ the corresponding function to modify it and to specify the default value "Ask your question here:"Ā
const [inputValue, setInputValue] = useState("Ask your question here")WhichĀ returns aĀ QuestionForm:Ā
import { useState } from 'react'
function QuestionForm() {
const [inputValue, setInputValue] = useState('Ask your question here')
return (
<div>
<textarea
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
</div>
)
}
export default QuestionFormĀ We passed a callback function to Ā onChangeĀ to saveĀ our input value inĀ our local state.Ā We'll access the typed input value with Ā e.target.valueĀ .Ā
inputValueĀ now has access to the content ofĀ our input at any time. We canĀ create a button that triggers an alert to renderĀ our input content, like this:Ā
<div>
<textarea
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={() => alert(inputValue)}>Alert me šØ</button>
</div>It works!
Itās great that I can access my input value, but why would I need to? š¤
It means you canĀ interact directly with the user's informationĀ and display an error message if the data is invalid or filter the data to intercept invalid values.Ā Ā
If we decide that the letter āfā is not valid (an odd example, I know), we can declare the variable:
const isInputError = inputValue.includes('f')
And display an error message (or not) according to this boolean:
{isInputError && (
<div>š„ You are not allowed to use the letter āfā here.</div>
)}Similarly, we can intercept invalid data entered by the user. To do this, declare an intermediate function:
function checkValue(value) {
if (!value.includes('f')) {
setInputValue(value)
}
}And apply the modification in the callback function:
onChange={(e) => checkValue(e.target.value)}Now, however many times you hammer away on the "f" key, the value will not register in your input.
You might not realize it just now, but this gives you great freedom as a developer in terms of the checks you want to create. Youāve got the power! š„
Great, I now know two methods, but when should I use controlled components and when should I use the uncontrolled version?!
Itās a case-by-case judgment. Youāll have to decide based on your constraints. When you have a quick component to do that isn't complex, uncontrolled input might be all you need. However, if you have checks to do, itās certainly better to use a controlled component. There seem to be many more controlled components in codebases.
There are also libraries that you can use to manage forms and their validation as cleanly as possible, such as the tool react-hook-form.
And there you go: youāre now ready to interact with your users through events and forms. š
Itās now time to put all of that into practice. Youāll find the codebase you need to get started on branch P2C5-Begin.Ā Ā
Here's a to-do list of things you can do to improve the app:
Create an alert that is triggered when a user clicks on the CareScale component that says:
"This plant requires a small/moderate/large amount of light/water" depending on the corresponding data and whether itās a water or light type CareScale component.Ā
Youāll find a new Ā FooterĀ component in the codebase. To this, you should add:
An input to get the userās email address, applying the controlled component method. The state syntax used in this chapter for Ā inputValueĀ and Ā setInputValueĀ that uses useState is also written in the codebase.
A Ā blurĀ event (when the user clicks outside of the field) that triggers an alert if inputValue doesnāt contain the @ character. This alert should say, "Error: no @ has been entered. This is not a valid email address."Ā
Youāll find the solution on branch P2C5-Solution.
In React, write events within a tag in Ā camelCaseĀ , and pass the function to be called.
Unlike in JS, youāllĀ seldom use Ā addEventListenerĀ .
React passes a synthetic event as a parameter of the callBack functions. This synthetic event is similar to a native event passed in the DOM, except that it is compatible with all browsers.
There are two main ways of managing form: controlled and uncontrolled. You are encouraged to use controlled forms.Ā
Controlled forms save the field values in the local state and access the data entered by the user with Ā onChangeĀ .
Controlled forms allow you to filter content or display an error message based on the data entered by the user.Ā
We've reached the end of Part 2. Itās now time to check your understanding in the quiz. Once youāve done that, we can launch into learning about state with React!