Components in React are independent, reusable pieces of UI. A typical web page may consist of a navbar, content area & footer. In React, we create these areas as components (which in turn may consist of other components!). It saves on code duplication & as we’ll see, allows for an immense amount of flexibility.
Another way to think of components is like JavaScript functions. Instead of receiving arguments, they receive “props”, and then return React elements to build what we see on the screen!
Components
In fact, in React — everything is a component! Even standard HTML tags are components, they’re built-in and added by default.
Let’s take a look at an example:
import React from 'react'
import ReactDOM from 'react-dom'
ReactDOM.render(<h1>I'm a component!</h1>,
document.getElementById('myapp'))
Here we’ve used JSX to insert<h1>I'm a component!</h1>
into an element with id of myapp
. Our h1
is considered a component, courtesy of React.DOM
, and in fact so are all HTML tags. You can check them out by typing React.DOM
into your browser console.
Building Custom Components
This is great, but how do we build our own components? This is where React exceeds, it gives us the ability to build UI’s by composing our own custom components.
We can define components in 2 ways, let’s take a look at each now:
Function Components
Function components are really just JavaScript functions:
function Greeting(props) {
return <h1>Hello, {props.username}!</h1>;
}
What makes this function a React component, is that it accepts “props” (or properties) as an argument with data, and then it returns a React element.
Class Components
ES6 Classes can also be used to create components:
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.username}!</h1>;
}
}
Both our above code examples are equivalent — and perfectly valid ways to create components.
Until recently in the React world, class components were used more frequently — as class components allowed components to be defined with their own state (I’ll be writing about state in my next article!).
However, with the advent of React Hooks, function components are now much more powerful than before, and we may see this trend switch back.
Hooks are outside the scope of this article! So let's continue on with components & props..
Rendering Components
We can render our elements, which represent DOM tags:
const element = <div />;
And we can also render our elements with user-defined components:
const element = <Greet username="Richard" />;
When an element contains a user-defined component, it will pass the JSX attributes to the component as an object. In React this object is what we call “props”.
Props
So “props” are how our components get their properties.
Let’s see this in action:
function Greeting(props) {
return <h1>Hello, {props.username}!</h1>;
}
const element = <Greet username="Richard" />;
ReactDOM.render(
element,
document.getElementById('root')
);
This code will render “Hello, Richard!” on the page.
What is happening here?
-
ReactDOM.render()
is called with the<Greet username="Richard" />
element. - React calls the
Greet
component with{name: 'Richard'}
as the props. - Our
Greet
component returns a<h1>Hello, Richard!</h1>
element as the result. - React DOM updates the DOM to match
<h1>Hello, Richard!</h1>
.
Note: Always start component names with a capital letter! Why? React treats components starting with lowercase letters as DOM tags.
Props in Function Components
It should be noted that when working with components that have multiple children (see below with h1
and p
), each child component gets its props from the parent.
When using a function component, props
are all that gets passed, they’re available by adding props as the function argument:
const BlogPostInfo = props => {
return (
<div>
<h1>{props.title}</h1>
<p>{props.description}</p>
</div>
)
}
Props in Class Components
In a class component, props are passed by default. They’re accessible as this.props
in a component instance.
import React, { Component } from 'react'
class BlogPostInfo extends Component {
render() {
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.description}</p>
</div>
)
}
}
Passing props to child components is a great way to pass values around in your applications. Components either hold data (have state) or receive data through their props.
Now that we know how to use props with our components. Let’s take a look at some of the more common tasks we’re likely to encounter:
Prop Defaults
If any values are missing when a component is initialized, we’ll need to provide a default. Defaults can be specified, like so:
BlogPostInfo.propTypes = {
title: PropTypes.string,
description: PropTypes.string
}
BlogPostInfo.defaultProps = {
title: '',
description: ''
}
Passing Props
When we initialize a component, we pass in our props like so:
const desc = 'My blog post description'
<BlogPostInfo title="My blog post title" description={desc} />
If we are working with strings, we can pass in our prop as a string (as we have above with ‘title’. Otherwise, we use variables, as we have with the above description being set to desc
.
The ‘children’ Prop
The children
prop is a little different from the norm. It contains the value of anything that is passed in the body
of the component, for example:
<BlogPostInfo title="My blog post title" description="{desc}">
More words
</BlogPostInfo>
In this example, inside BlogPostInfo
we could access "More words" via this.props.children
.
Components in Components
Components can include other components in their output.
It’s perfectly fine to create a MyApp
component, that renders Greet
a number of times:
function Greet(props) {
return <h1>Hello, {props.username}!</h1>;
}
function MyApp() {
return (
<div>
<Greet name="Bruce" />
<Greet name="Bethany" />
<Greet name="Bilbo" />
</div>
);
}
ReactDOM.render(
<MyApp />,
document.getElementById('root')
);
Props are Read-Only!
Whether your component is declared as a function or class component, it can never modify its own props. See the following example:
function sum(a, b) {
return a + b;
}
This is a “pure” function, as it doesn’t attempt to change its inputs, and will always return the same result for the same inputs.
An “impure” function is a function that changes its own input:
function withdraw(account, amount) {
account.total -= amount;
}
In React, this is a no-no! Every component must act like a pure function with respect to its prop.
My next article will be looking at “state” in React. With state, our components are able to change their output in response to triggers such as user actions or network responses — without being in violation of this rule.
Summary
There we go! We’ve covered the basics of building components, as well as seeing how they fit into the overall structure of our React apps. We’ve also seen how to use props to give properties to our components, and we’ve looked at some of the common tasks we’ll likely run into when working with components & props.
Conclusion
If you liked this blog post, follow me on Twitter where I post daily about Tech related things!
If you enjoyed this article & would like to leave a tip — click here