Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This course is archived!
While the concepts of this course are still largely applicable, it's built using an older version of Symfony (4) and React (16).

Handling Events (like onClick)!

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

I want to do something when the user clicks the tr element. In React, how can we attach event listeners? What is the React version of selecting an element in jQuery and adding an on click function?

Attaching an Event

Oh, you're going to love... or maybe hate the answer. I love it, because it's simple! To add a click handler to this tr add... onClick and pass this a function. I'll use an arrow function and, for now, just console.log('OMG - an onClick!').

... lines 1 - 11
render() {
... lines 13 - 26
return (
... lines 28 - 40
{repLogs.map((repLog) => (
<tr
... lines 43 - 44
onClick={() => console.log('OMG an onClick!') }
>
... lines 47 - 51
))}
... lines 53 - 100
);
}
... lines 103 - 104

Move over, refresh, click, and... find the terminal. Boom!

Updating with this.setState()

Cool. Let's review our goal: to highlight a row when we click on it. So... hmm... onClick: if we could update the highlightedRowId state to the correct id, React would re-render and take care of the rest! Easy! Inside the arrow function, update the state with this.setState(). Pass this an object with the state key or keys that you want to change. For us, highlightedRowId set to the id of this rep log: repLog.id.

... lines 1 - 40
{repLogs.map((repLog) => (
<tr
... lines 43 - 44
onClick={() => this.setState({highlightedRowId: repLog.id}) }
>
... lines 47 - 51
))}
... lines 53 - 104

Coolio! But, an important note! In the constructor, we initialized the state by setting the this.state property directly. This is the only place, ever, that you will change or set the state property directly. Everywhere else, always, you need to call this.setState(). If you don't, puppies will stare at you with sad eyes.

And, more important, if you modify the state property directly, React won't re-render. The reason is simple: this is what React uses to know that you changed the state and so, to start the re-rendering.

Bah, let's go try it already! Refresh! And... click! Woohoo! We just added our first bit of interactivity. In the React dev tools, if you click on RepLogApp, you can watch the highlightedRowId state change as we click the rows. Pretty freaking cool.

The SyntheticEvent

Just like with jQuery or plain JavaScript, when you add an event callback, your function is passed an event object. We don't need the event in this case, but it contains all the same information you're used to having. Actually, this isn't a native DOM "event" object. React passes you what's called a "SyntheticEvent": an event object that wraps the normal event, has all the same methods and properties, but adds a few things to make life easier.

... lines 1 - 41
<tr
... lines 43 - 44
onClick={(event) => this.setState({highlightedRowId: repLog.id}) }
>
... lines 47 - 104

Moving the Handler to the Class

Putting all this logic inline is fine... but it can become hard to read. So, instead, I like to make the handler a property on my class. Start by adding a new method: handleRowClick that will accept the repLogId that was just clicked and also the event object itself... just to show that we can we pass this:

Next, steal the state-setting code and paste it here, but with highlightedRowId set to repLogId. And... we should probably close the method so Webpack isn't so mad at me!

... lines 1 - 11
handleRowClick(repLogId, event) {
this.setState({highlightedRowId: repLogId});
}
... lines 15 - 108

Below, call it: this.handleRowClick() with repLog.id and event.

... lines 1 - 15
render() {
... lines 17 - 30
return (
... lines 32 - 45
<tr
... lines 47 - 48
onClick={(event) => this.handleRowClick(repLog.id, event)}
>
... lines 51 - 104
);
}
... lines 107 - 108

I like it! Let's make sure we didn't bork our cool app: back to the browser! Refresh! Yea! It still works!

This is the power of React! It doesn't care how many different things in your UI need to change when some state changes, it takes care of everything.

And now, it's time to talk about organization. RepLogApp is big, and when things get too big, they get confusing. Let's move some code into a new child component.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

While the concepts of this course are still largely applicable, it's built using an older version of Symfony (4) and React (16).

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^1.6", // 1.9.1
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.3
        "doctrine/doctrine-fixtures-bundle": "~3.0", // 3.0.2
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.1
        "doctrine/orm": "^2.5", // v2.7.2
        "friendsofsymfony/jsrouting-bundle": "^2.2", // 2.2.0
        "friendsofsymfony/user-bundle": "dev-master#4125505ba6eba82ddf944378a3d636081c06da0c", // dev-master
        "sensio/framework-extra-bundle": "^5.1", // v5.2.0
        "symfony/asset": "^4.0", // v4.1.4
        "symfony/console": "^4.0", // v4.1.4
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/form": "^4.0", // v4.1.4
        "symfony/framework-bundle": "^4.0", // v4.1.4
        "symfony/lts": "^4@dev", // dev-master
        "symfony/monolog-bundle": "^3.1", // v3.3.0
        "symfony/polyfill-apcu": "^1.0", // v1.9.0
        "symfony/serializer-pack": "^1.0", // v1.0.1
        "symfony/swiftmailer-bundle": "^3.1", // v3.2.3
        "symfony/twig-bundle": "^4.0", // v4.1.4
        "symfony/validator": "^4.0", // v4.1.4
        "symfony/yaml": "^4.0", // v4.1.4
        "twig/twig": "2.10.*" // v2.10.0
    },
    "require-dev": {
        "symfony/debug-pack": "^1.0", // v1.0.6
        "symfony/dotenv": "^4.0", // v4.1.4
        "symfony/maker-bundle": "^1.5", // v1.5.0
        "symfony/phpunit-bridge": "^4.0", // v4.1.4
        "symfony/web-server-bundle": "^4.0" // v4.1.4
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "dependencies": {
        "@babel/plugin-proposal-object-rest-spread": "^7.12.1" // 7.12.1
    },
    "devDependencies": {
        "@babel/preset-react": "^7.0.0", // 7.12.5
        "@symfony/webpack-encore": "^0.26.0", // 0.26.0
        "babel-plugin-transform-object-rest-spread": "^6.26.0", // 6.26.0
        "babel-plugin-transform-react-remove-prop-types": "^0.4.13", // 0.4.13
        "bootstrap": "3", // 3.3.7
        "copy-webpack-plugin": "^4.4.1", // 4.5.1
        "core-js": "2", // 1.2.7
        "eslint": "^4.19.1", // 4.19.1
        "eslint-plugin-react": "^7.8.2", // 7.8.2
        "font-awesome": "4", // 4.7.0
        "jquery": "^3.3.1", // 3.3.1
        "promise-polyfill": "^8.0.0", // 8.0.0
        "prop-types": "^15.6.1", // 15.6.1
        "react": "^16.3.2", // 16.4.0
        "react-dom": "^16.3.2", // 16.4.0
        "sass": "^1.29.0", // 1.29.0
        "sass-loader": "^7.0.0", // 7.3.1
        "sweetalert2": "^7.11.0", // 7.22.0
        "uuid": "^3.2.1", // 3.4.0
        "webpack-notifier": "^1.5.1", // 1.6.0
        "whatwg-fetch": "^2.0.4" // 2.0.4
    }
}
userVoice