4.1 React Components & Props
# What is a component?
When building applications with React, think about how to break down your UI (user interface) design into small widgets. Fundamentally, React Components are just special JavaScript functions that returns some JSX composed of one or more React Elements to describe the look and behaviour of one of those widgets.
These component functions accept a single argument, which is an object called props
.
function GreetPerson (props) {
return <h1>Hello {props.name}</h1>
}
The component can then be used by name like a custom HTML element in JSX. The name
property gets passed into the function by setting an attribute on that custom component when the component is used in some other function's JSX.
function WelcomePage () {
return (
<main>
<GreetPerson name='Mickey' />
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Recusandae
quas quis quia incidunt illum aut culpa omnis. Dicta fugit sapiente
dolor eveniet numquam, cum provident recusandae mollitia. Illo, qui a.
</p>
</main>
)
}
PascalCase component names
React component names should always start with an upper-case letter. Otherwise the JSX interpreter will think it is a regular HTML element and not compile it correctly.
# Default App component
The basic scaffolding for a React project website starts in /src/index.js
where it imports the top level application component, usually called App.js
, and mounts it to the DOM using the ReactDOM.render()
method.
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
ReactDOM.render(<App />, document.getElementById('root'))
registerServiceWorker()
TIP
See how the App component is rendered as JSX like <App />
.
The /src/App.js
module is the top-level ancestor component from which all other application components will descend. We typically talk about "composing the UI", meaning that we assemble all of the various components like building blocks to describe the complete user interface.
import React from 'react'
import logo from './logo.svg'
import './App.css'
function App () {
return (
<div className='App'>
<header className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className='App-link'
href='https://reactjs.org'
target='_blank'
rel='noopener noreferrer'
>
Learn React
</a>
</header>
</div>
)
}
export default App
# Decomposing a design
Let's start with a simple website layout and walk through the process of building this with React.
# What is the structure?
header
- logo
- nav
- nav-link
content-body
hero
- p
- button
main
- h1
- p * 3
# Start in the App component
Build out the JSX for this layout entirely in the App component, for now.
import React from 'react'
import './App.css'
function App () {
return (
<div className='App'>
<header className='App-header'>
<div className='App-logo'>MAD&D</div>
<nav className='TopNav'>
<a href='#' className='TopNav-link'>
Courses
</a>
<a href='#' className='TopNav-link'>
Profs
</a>
<a href='#' className='TopNav-link'>
Required Equipment
</a>
</nav>
</header>
<div className='App-body'>
<div className='HeroBlock'>
<p>Some amazing claim!</p>
<button className='HeroBlock-button'>Call to action</button>
</div>
<main>
<h1>Main Heading</h1>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Recusandae
quas quis quia incidunt illum aut culpa omnis. Dicta fugit sapiente
dolor eveniet numquam, cum provident recusandae mollitia. Illo, qui
a.
</p>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Recusandae
quas quis quia incidunt illum aut culpa omnis. Dicta fugit sapiente
dolor eveniet numquam, cum provident recusandae mollitia. Illo, qui
a.
</p>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Recusandae
quas quis quia incidunt illum aut culpa omnis. Dicta fugit sapiente
dolor eveniet numquam, cum provident recusandae mollitia. Illo, qui
a.
</p>
</main>
</div>
</div>
)
}
export default App
OK. That is the basic structure, but let's add some CSS to the App.css
file so that it looks usable.
.App-logo {
font-size: 1.5rem;
pointer-events: none;
}
.App-header {
background-color: hsl(220, 13%, 18%);
color: hsl(193, 95%, 97%);
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.5rem;
}
.TopNav {
display: flex;
align-items: center;
justify-content: flex-end;
}
.TopNav-link {
color: hsl(193, 95%, 68%);
font-size: 1.125rem;
font-weight: 500;
margin-left: 1.25rem;
letter-spacing: 0.125px;
text-decoration: none;
text-transform: uppercase;
}
.App-body {
max-width: 80vw;
margin: 0 auto;
}
.HeroBlock {
background-color: hsl(193, 95%, 68%);
border-radius: 0.5rem;
box-shadow: 0 2px 8px 0 hsl(220, 13%, 78%);
color: hsl(220, 13%, 18%);
font-size: 3rem;
margin: 1.5rem 0;
padding: 1.5rem;
text-align: center;
}
main {
margin-top: 2.5rem;
}
.HeroBlock-button {
background-color: hsl(193, 95%, 97%);
border-radius: 0.25rem;
border: 1px solid transparent;
box-shadow: 0 2px 8px 0 hsl(220, 30%, 72%);
font-size: 1.25rem;
padding: 0.5rem 1rem;
}
.HeroBlock-button:focus,
.HeroBlock-button:hover {
background-color: hsl(220, 13%, 18%);
color: hsl(193, 95%, 97%);
}
.HeroBlock-button:active {
background-color: hsl(220, 13%, 10%);
box-shadow: 0 2px 4px 0 hsl(220, 30%, 72%);
color: hsl(193, 95%, 97%);
}
# What can be broken out into separate components?
Identify which elements can be encapsulated into their own custom components. For example, the nav.TopNav
... create a new TopNav.js
file with this outline of a React component function.
import React from 'react'
function TopNav () {
return <div></div>
}
export default TopNav
Now cut and paste to replace the empty <div>
above with the <nav>
markup from App.js
.
import React from 'react'
function TopNav () {
return (
<nav className='TopNav'>
<a href='#' className='TopNav-link'>
Courses
</a>
<a href='#' className='TopNav-link'>
Profs
</a>
<a href='#' className='TopNav-link'>
Required Equipment
</a>
</nav>
)
}
export default TopNav
Great! Now, update App.js
to import this new component and use it in the returned JSX.
import React from 'react'
import './App.css'
import TopNav from './components/TopNav'
function App() {
return (
<div className="App">
<header className="App-header">
<div className="App-logo">MAD&D</div>
<TopNav />
</header>
/* The rest of the file ... */
# Returning an array of JSX
In the TopNav component, we can reduce the repetition in our code and make the menu more data driven.
Add a new variable above the function declaration ...
const menuItems = [
{ id: 1, linkTitle: 'Courses', url: '#' },
{ id: 2, linkTitle: 'Profs', url: '#' },
{ id: 3, linkTitle: 'Required Equipment', url: '#' }
]
Then replace the three <a>
elements with this code to map over the menuItems
array and return a new array replacing the menu item objects with the JSX to display those menu items.
<nav className='TopNav'>
{menuItems.map(item => (
<a href={item.url} className='TopNav-link'>
{item.linkTitle}
</a>
))}
</nav>
# Pass menu items array as props
Now suppose that the data for the menu items was being loaded dynamically in the top level App.js
component. We need to pass it down to the TopNav
component via props.
// TopNav.js
import React from 'react'
function TopNav (props) {
return (
<nav className='TopNav'>
{props.menuItems.map(item => (
<a href={item.url} className='TopNav-link'>
{item.linkTitle}
</a>
))}
</nav>
)
}
export default TopNav
// App.js
import React from 'react'
import './App.css'
import TopNav from './components/TopNav'
const menuItems = [
{id: 1, linkTitle: 'Courses', url: '#'},
{id: 2, linkTitle: 'Profs', url: '#'},
{id: 3, linkTitle: 'Required Equipment', url: '#'}
]
function App() {
return (
<div className="App">
<header className="App-header">
<div className="App-logo">MAD&D</div>
<TopNav menuItems={menuItems} />
</header>
/* The rest of the file ... */
# Practice time
Extract separate component modules for the HeroBlock
and the MainArticle
with these props:
HeroBlock: valueStatement, buttonLabel
MainArticle: headline, bodyText
TIP
React automatically escapes content passed as props when inserted into JSX. This helps prevent XSS attacks. However, there may be times when you need to override this behaviour.
See the React Docs for dangerouslySetInnerHTML
solution files
Caught you peeking!
# Encapsulate the CSS with the component
To truly make your components reusable, move the relevant CSS from the App.css
file to new component specific CSS files. e.g. HeroBlock.css
# Rules
# Props are Read-Only
All React components must act like pure functions with respect to their props.
The props received in a component should be treated as immutable — never try to directly change the value. If you need to manipulate the given input value, make a copy of it in another variable, or use a non-mutating function like Array.map()
that returns a new array.
Read more about pure functions.
Props can be any valid JavaScript data type
Props are how we pass everything from one component to another.
Props can be Strings, Numbers, Booleans, Arrays, Objects, or even functions.
# Before next class
# VS Code Extensions
# React Docs - Main Concepts (sections 1, 2, 3, 4)
1. Hello World
2. Introducing JSX
3. Rendering Elements
4. Components and Props