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="Bruce" />;

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="Bruce" />;


ReactDOM.render(
  element,
  document.getElementById('root')
);

This code will render “Hello, Bruce!” on the page.

What is happening here?

  • ReactDOM.render() is called with the <Greet username="Bruce" /> element.
  • React calls the Greet component with {name: 'Bruce'} as the props.
  • Our Greet component returns a <h1>Hello, Bruce!</h1> element as the result.
  • React DOM updates the DOM to match <h1>Hello, Bruce!</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.

Extra credits…

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.

Conclusion

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

Related Posts:


Tim profile image

A little about me..

Hey, I’m Tim! 👋

I’m a freelance business owner, web developer & author. I teach both new and experienced freelancers how to build a sustainable and successful freelancing business. Check out my Complete Guide to Freelancing if you'd like to find out more.

While you're here, you can browse through my blogs where I post freelancing tips, code tutorials, design inspiration, useful tools & resources, and much more! You can also join the newsletter, or find me on X.

Thanks for reading! 🎉