text

Building a user interface with React components
One of the keys to building out user interfaces with React is to create reusable components. These can be used in many areas of an application, as needed. Examples can include buttons, thumbnails, comment sections, and more.
By making use of function components and passing props to them, props data can be rendered inside of JSX to customize otherwise generic components – like changing the name or color of a button, or the image for a thumbnail, or adding a new comment. This is often done using nested components which rely on props from a parent component to render part of a UI.
A nested component is one that’s called from inside of another component. As stated, they often take in props from the parent component.
const Band = () => {
return (
<div>
<h2>Napalm Death</h2>
<Album
album="Scum"
year="1987"
song="Multinational Corporations"
lyric="Genocide of the starving nations"
/>
</div>
)
}
const Album = (props) => {
return (
<div>
<h3>{props.album}, {props.year}</h3>
<img src={require('../img/'+`${props.album}`+'.jpg')} alt=`${props.album}`/>
<Song song={props.song} lyric={props.lyric} />
</div>
)
}
const Song = props =>
return (
<p><b>{props.song}</b></p>
<p>{props.lyric}</p>
)
}
I know the components above are a bit messy and could be broken into further child components, but they illustrate that Band has Album nested in it, and Album nests Song. Band passes four named props to Album, which renders two of them and passes the other two to Song, which finally, renders them. To illustrate an additional use of the “album” prop, I used it not only in an <h3> but also in a path to an image for an album cover, and as alt text for screenreaders. Its actually the same technique I used on the sprint challenge for this unit when I took it in WEBPT10, to render local images for Star Wars characters onscreen. Its recommended both at Lambda and in other sources, like React’s official documentation, not to drill deeper than 4 levels when passing props.
As mentioned above, passing props down to child components is how we can do things like create buttons that share the same style but different text, or image thumbnails that are formatted the same but show different pictures and link to different image files, and so on. Making them unique or dynamic also ties into the next section:
Passing props to a React component as dynamic data
So, the examples above and in my previous post relied on static data to work. The props in <Album /> were never going to change because they’re hard-coded. In order to change that, we need to pass dynamic data to our components. Dynamic data is simply data that can change. If I passed in information for different albums, whether I read them from a local array or from an external API, that data would now be dynamic, because its not hard-coded in my component. Basically, for each pass through the components, they would render something different: a new album.
Right now, our component flow is Band -> Album -> Song. To make the whole application render different albums, or even different bands’ catalogs dynamically, we could add a parent component to Band that is stateful and passes state data with band information in it to Band as props. Band would then send that props data further down the rabbit hole to its child components and render albums dynamically.
Since we’re using function components and hooks, we start by importing the .useState() hook into the parent application.
import React, { useState } from 'react';
Next, we would use .useState() in our function component to create a slice of state, a function to update that state, and optionally, a starting value for state.
function App() {
const [band, setBand] = useState();
return (
<div> className='App'>
<Band band={band} />
</div>
)
}
Ok. I just did that thing that I hated, where I set props equal to a value with the same name as it (band={band}). Sadly, its the norm and I named <Band />, <Album /> and <Song /> that way, too, above just to drill it into my own head as much as anyone else’s who reads this. Anyway, here are some details about the App() function:
- All React component functions needs to start with a capital letter.
- The filenames also need to start with a capital letter.
- “class” can’t be used in JSX. The equivalent is “className”. This is because “class” is a reserved word in JavaScript, so we can’t use the HTML attribute with the same name.
- <Band band={band} /> means call the component “Band” and pass it a prop called “band” with data from the slice of state called {band}. Apologies about that.
- Think about that 2nd part more as something like bandInfoProps=bandState, if that makes more sense.
Finally, we’d need to modify the <Band /> component to work with props from the <App /> component. And we’d need to read data for all of this into <App /> from somewhere, whether its a local array or an API from the wild. <Band /> could look something like this:
const Band = (props) => {
return (
<div>
<h2>{props.name}</h2>
<Album
album={props.album}
year={props.year}
song={props.album.song.title}
lyric={props.album.song.lyrics}
/>
</div>
)
}
My assumption is that in our data, each band would have an array of albums which would also have an array of songs and each song would have a title and lyrics. To use this in our application, we’d have to read that data from somewhere, set it to state and then state would pass it along as props and let the components do their thing. Getting that data could be something that we automatically do when the application launches (we can set an initial state with a particular band, album and song) or could happen when a user triggers it, like by clicking a button.
We’ll look at this more in my recap about the next lesson, which will discuss side effects, .useEffect() hook and getting data from an API. Oh, and all of the components above would need to have the right imports and exports. <Band />, <Album /> and <Song /> would probably use “export default” with their main functions and each parent component would import its child, so App() would import “Band” and “Band” would import “Album” and “Album” would import “Song”.