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

The key Prop & Inline Rendering

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

We just rendered an array of React <tr> element objects. And as a thank you, React has awarded us with a big ugly error! It says:

Warning: each child in an array should have a unique "key" prop.

Rude! Here we are, with a perfectly functional table, and React is ruining our magical moment. Well... ok, it's warning us for a good reason. And, PhpStorm was also trying to help.

Why a Collection needs a key

Here's the deal: soon, we're going to use React to perform automagical updates to the UI when data changes. Eventually, we'll use this to add and remove rows to this table as we create and delete rep logs! But... when you have a collection of items like this, if we update the data on one of the rep logs, React isn't totally sure which row to update in the DOM. For example, if this rep log's weight suddenly changed to 150, it's possible that React would update the wrong row!

To help React, we need to give each row a unique key - kind of like how each row in a database table has a primary key. To do this, go to the outer-element of each item and literally add a key prop. This needs to be something that is unique and won't change. So, basically, it should be the id.

... lines 1 - 2
export default class RepLogApp extends Component {
render() {
... lines 5 - 15
const repLogElements = repLogs.map((repLog) => {
return (
<tr key={repLog.id}>
... lines 19 - 23
)
});
... lines 26 - 54
}
}

Solved! This key prop isn't a big deal, it's just a chore you need to handle each time you render a collection. But don't worry: if you forget, React will remind you!

Try it now: head over and refresh! The page still works, and the warning is gone!

Rendering Inline

There's one minor downside to this new setup. Up here, we use the map function to create an array of repLogElements. Down below, we render that.

What's the problem? Well, just that, if you're looking at render() to see your markup, when you see {repLogElements}, you need to scroll back up to see what this is. Whenever possible, it's better to keep all of your markup in one place.

And, we can do that... by being a bit clever. Copy the repLogs.map() code, then delete the repLogElements variable entirely. Back inside JSX, clear out the variable and... paste!

... lines 1 - 15
return (
... lines 17 - 19
<table className="table table-striped">
... lines 21 - 28
<tbody>
{repLogs.map((repLog) => {
return (
<tr key={repLog.id}>
<td>{repLog.itemLabel}</td>
<td>{repLog.reps}</td>
<td>{repLog.totalWeightLifted}</td>
<td>...</td>
</tr>
)
})}
</tbody>
... lines 41 - 48
</table>
... lines 50 - 51
);
... lines 53 - 55

That's it! It's really the same thing we had before! This loops over the repLogs array, builds an array of "rep log" element objects, then... prints them!

Try it! Move over and, refresh! Yes!

At first, the syntax may look weird. But, it's now very obvious that inside the tbody, we are printing a bunch of tr elements.

Shorter Arrow Functions

And if this isn't fancy enough for you, well, you won't be disappointed. If you're still getting used to how the arrow functions look, you may not love this next change. But, if it's too weird, don't use it!

Because the arrow function is, um, a function, we usually surround the body of the function with curly braces. But, if the only line in your function is the return statement, you can remove the curly braces and just put the code for the return. Oops, I have one extra curly brace.

... lines 1 - 28
<tbody>
{repLogs.map((repLog) => (
<tr key={repLog.id}>
<td>{repLog.itemLabel}</td>
<td>{repLog.reps}</td>
<td>{repLog.totalWeightLifted}</td>
<td>...</td>
</tr>
))}
</tbody>
... lines 39 - 53

We now have a function with one argument that returns this JSX element.

Move over and try it! Woohoo! It works! These are the types of little things in React that you don't need to do. And, if it makes your head spin, keep it simple. But, I want you to at least know about these tricks. Because, often, it's these types of shortcuts that end up making React look hard.

Let's finish building the static version of our app next: by adding the form!

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