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!

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best