In this chapter, we look at what all of this means. More specifically, we look at two points:
The boring technical stuff you need to know
The boring stuff you need to know to identify components when you look at a bunch of visual elements
Okay, what you’re going to learn isn’t actually that boring. I’m just setting your expectations really low.
The examples we’ve looked at so far have been pretty basic. They were great for highlighting technical concepts, but they weren’t great for preparing you for the real world.
In the real world, what you’ll be asked to implement in React will never be as simple as a list of names or colorful blocks of vowels. Instead, you’ll be given a visual of some complex user interface, such as a scribble, diagram, screenshot, video, redline, or comp. Then it’ll be up to you to bring all those static pixels to life. You’ll get some hands-on practice in this chapter doing just that.
The task here is to build a simple color palette card (see Figure 5.1).
Color palette cards are small rectangular cards that help you match a color with a particular type of paint. You can see them in home improvement stores or anywhere paint is sold. Your designer friend probably has a giant closet dedicated to them in his or her place. Anyway, our mission is to re-create one of these cards using React.
We could go about this in several ways, but let’s take a systematic approach that simplifies and make sense of even the most complex user interfaces. This approach involves two steps:
1. Identify the major visual elements.
2. Figure out what the components will be.
Both of these steps sound really complex, but as we walk through this, you’ll see that you have nothing to worry about.
The first step is to identify all the visual elements we’re dealing with. No visual element is too minor to omit—at least, not initially. The easiest way to identify the relevant pieces is to start with the obvious visual elements and then dive into the less obvious ones.
The first thing you will see in our example is the card itself (see Figure 5.2).
Within the card are two distinct regions. The top region is a square area that displays a particular color. The bottom region is a white area that displays a hex value.
Let’s call out these two visual elements and arrange them into a treelike structure, as shown in Figure 5.3.
Arranging your visuals into this treelike structure (a.k.a. a visual hierarchy) is a good way to get a better feel for how your visual elements are grouped. The goal of this exercise is to identify the important visual elements and break them into a parent/child arrangement until you can divide them no further.
Try to Ignore Implementation Details
It might be hard, but don’t think about the implementation details yet. Don’t focus on dividing your visual elements based on what combination of HTML and CSS is required. You’ll have plenty of time for that later.
Continuing on, we can see that our colorful square isn’t something we can divide further. That doesn’t mean we’re done, though. We can further divide the label from the white region that surrounds it. Right now, our visual hierarchy looks as shown in Figure 5.4, with our label and white region occupying a separate spot in our tree.
At this point, we have nothing else to divide any further. We’re finished identifying and dividing up our visual elements, so the next step is to use what we’ve found to help us identify the components.
This is where things get a little interesting. We need to figure out which of the visual elements we’ve identified will be turned into components and which ones will not. Not every visual element needs to be turned into a component, and we also don’t want to create only a few extremely complex components. We need to strike a balance (see Figure 5.5).
There’s an art to figuring out which visual elements become part of a component and which don’t. The general rule is that components should do just one thing. If you find that your potential component will end up doing too many things, you probably want to break it into multiple components. On the flipside, if your potential component does too little, you probably want to skip making that visual element a component altogether.
Let’s try to figure out which elements would make good components in our example. From looking at our visual hierarchy, both the card and the colored square seem like they fit the bill for making a great component. The card acts as the outer container, and the colored square simply displays a color.
That just puts a question mark around our label and the white region it is surrounded by (see Figure 5.6).
The important part here is the label itself. Without it, we can’t see the hex value. That leaves just the white region. It serves a negligible purpose; it is simply empty space, and that responsibility can easily be handed off to our label itself. Brace yourself for what I’m about to say next: Sadly, our white rectangular region will not be turned into a component.
At this point, we have identified our three components, and the component hierarchy looks like Figure 5.7.
An important point to note is that the component hierarchy has more to do with helping us define our code than it does with how the finished product will look. You’ll notice that it looks a bit different than the visual hierarchy we started with. For visual details, always refer to your source material (a.k.a. your visual comps, redlines, screenshots, and other related items). To figure out which components to create, you should use the component hierarchy.
Okay, now that we’ve identified our components and the relationships among all of them, it’s time to start bringing our color palette card to life.
This is the easy part…sort of! It’s time to start writing some code. First we need a mostly empty HTML page that will serve as our starting point:
Take a moment to see what this page has going on. There isn’t much: just the bare minimum needed to have React render an empty
div into our container element.
After you’ve done this, it’s time to define our three components. The names we’ll go with for our components are Card, Label, and Square. Go ahead and add the following lines just above the
Besides declaring our three components, we threw in the
render function that each component absolutely needs to function. Each
render function returns a simple
br element for now; leaving the return value for the
render function empty throws an error. Other than that, our components are empty. In the following sections, we’ll fix that by filling them in.
Let’s start at the top of our component hierarchy and first focus on our
Card component. This component will act as the container where our
Label components will live.
To implement it, go ahead and make the following highlighted modifications:
This seems like a lot of changes, but most of the lines are going into styling the output of our Card component via the
cardStyle object. The rest of the changes are pretty unimpressive. We return a
div element, and that element’s
style attribute is set to our
cardStyle object. Now, to see our Card component in action, we need to display it in our DOM as part of the
ReactDOM.render function. To make that happen, go ahead and make the following highlighted change:
All we’re doing is telling the
ReactDOM.render function to render the output of our Card component by invoking it. If everything worked out properly, you’ll see a result identical to Figure 5.8 if you test your app.
Yes, it’s just the outline of the color palette card, but that’s definitely more than what you started with just a few moments ago!
It’s time to go one level down in our component hierarchy and look at our Square component. This is a pretty straightforward one, so make the following highlighted changes:
As with our Card component, we are returning a
div element whose
style attribute is set to a style object that defines how this component looks. To see our Square component in action, we need to get it onto our DOM just like we did with the Card component. The difference this time around is that we won’t be calling the Square component via our
ReactDOM.render function. Instead, we’ll call the Square component from inside the Card component. To see what I mean, go back to our Card component’s
render function and make the following change:
At this point, if you preview your app, you’ll see a colorful square making an appearance (see Figure 5.9).
The cool thing to call out is that we called our Square component from inside the Card component! This is an example of component composability, in which one component relies on the output of another component. The final thing you see is the result of these two components colluding with each other. Isn’t collusion just beautiful…at least in this context?
The last component that remains is our Label. Go ahead and make the following highlighted changes:
The pattern of what we’re doing should be routine to you by now. We have a style object that we assign to what we return. We return a
p element whose content is the string
#FF6663. To have what we return ultimately make it to our DOM, we need to call our Label component via our Card component. Go ahead and make the following highlighted change:
Notice that our Label component lives just under the Square component we added to our Card component’s
return function earlier. If you preview your app in the browser now, you should see something that looks like Figure 5.10.
Yes, that’s right! Our color palette card is done and visible, thanks to the efforts of our Card, Square, and Label components. That doesn’t mean we’re done yet, though. We have a few more things to cover.
In our current example, we hard-coded the color value used by our Square and Label components. That’s an odd thing to do. It might or might not have been done deliberately for dramatic effect, but fixing it is straightforward. The solution just involves specifying a property name and accessing it via
this.props. You’ve seen all this before; the only difference is the number of times you have to do this.
There’s no way to properly specify a property on a parent component and have all descendants automatically gain access to that property. There are many improper ways to deal with this, such as defining global objects and directly setting the value on a component property. We won’t concern ourselves with such improper solutions right now, though. We aren’t animals!
The proper way to pass a property value to a child component is to have each intermediate parent component pass on the property as well. To see this in action, take a look at the highlighted changes to our current code. We move away from a hard-coded color and instead define our card’s color using a color property:
After you’ve made this change, you can specify any hex color you want as part of calling the Card component:
The resulting color palette card features the color you specified (see Figure 5.11).
Now let’s go back to the changes we made. Even though the color property is consumed by only the Square and Label components, the parent Card component is responsible for passing the property on to them. For even more deeply nested situations, you’ll have more intermediate components that will be responsible for transferring properties. It gets worse. When you have multiple properties that you want to pass around multiple levels of components, the amount of typing (or copying/pasting) you do increases a lot as well. There are ways to mitigate this, and we’ll look at those mitigations in much greater detail in a future chapter.
This markup has no idea how it got there. It doesn’t know about which components were responsible for what. It doesn’t care about component composability or the frustrating way we had to transfer the
color property from parent to child. That brings up an important point to make.
If we had to generalize the end result of what components do, all they do is return blobs of HTML to whatever called it. Each component’s
render function returns some HTML to another component’s
render function. All of this HTML keeps accumulating until a giant blob of HTML is pushed (very efficiently) to our DOM. That simplicity is why component reuse and composability works so well. Each blob of HTML works independently from other blobs of HTML, especially if you specify inline styles as React recommends. This allows you to easily create visual elements from other visual elements without having to worry about anything. Anything! Isn’t that pretty freaking awesome?
As you might have realized by now, we are slowly shifting focus toward the more advanced scenarios that React thrives in. Actually, advanced isn’t the right word. The correct word is realistic. In this chapter, you started by learning how to look at a piece of UI and identify the components in a way that you can later implement. You’ll find yourself in that situation all the time. While the approach we employed seemed really formal, as you get more experienced with creating things in React, you can ratchet down the formality. If you can quickly identify the components and their parent/child relationships without creating a visual and component hierarchy, that’s one more sign that you are getting really good at working with React.
Identifying the components is only one part of the equation. The other part is bringing those components to life. Most of the technical stuff you saw here was just a minor extension of what you’ve already seen. We looked at one level of components in an earlier chapter, and here we looked at how to work with multiple levels of components. We looked at how to pass properties between one parent and one child in an earlier chapter, and here we looked at how to pass properties among multiple parents and multiple children. Maybe in a future chapter we’ll do something groundbreaking, like drawing multiple color palette cards to the screen! Or maybe we can specify two properties instead of just a single one. Who knows?
Note: If you run into any issues, ask!
If you have any questions or your code isn’t running like you expect, don’t hesitate to ask! Post on the forums at https://forum.kirupa.com and get help from some of the friendliest and most knowledgeable people the Internet has ever brought together!