• 8 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 11/8/22

Interact With Components Using Events

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. 😉

Discover the React Events Syntax

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.
Our alert isn't quite working yet.

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! 😎

Use Synthetic Events

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

Create Forms More Easily With React

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.  

Delegate Control Using Uncontrolled 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.

Take Control of Your Forms

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? 🤔

Understand the Benefits of Controlled Forms

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. 😎

Give It a Go!

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.

Let’s Recap!

  • 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!

Example of certificate of achievement
Example of certificate of achievement