React Components

all the way down

A Basic Component

// App.js
import React from 'react';

function App() {
  return (
    <div>
      <h1>Welcome to React</h1>
      <p>This is some basic content.</p>
    </div>
  );
}
export default App;

We use ES2015 (ES6) style import/exports to include react.

Our App function returns what looks like HTML but is actually something called JSX.


JSX

JSX lets us blur the lines between JavaScript and HTML by allowing us to write code like this:

const element = <h1>Hello, world!</h1>;

This is a variable that's holding a reference to an h1 element.

We can define that JSX inline...

function Header() {
  return (
    <header>
      <div className="logo">
          <img src="static/img/logo.png" alt="Logo" />
      </div>
    </header>
  );
}

export default Header

Rendering a JSX Variable

We can also render a variable that's holding some JSX like this:

import React from "react";

function App() {
  const logo = <img src="static/img/logo.png" alt="Logo" />;
  return (
    <header>
      <div className="logo">
          {logo}
      </div>
    </header>
  );
}

export default App;

The curly braces around the {logo} reference let us write JavaScript inside our JSX.


Rendering a Sub-Component

We can also import a Component from another file and render it like so:

import Logo from './Logo';
function Header() {
  return (
    <header>
      <Logo />
    </header>
  );
}

export default Header

That's really powerful, because it lets us break a complex UI down into smaller pieces.

React gives us the ability to use encapsulation and abstraction in tandem with the expressiveness of HTML.


class and className in JSX

Did you notice the className attribute in the earlier example?

function Header {
  return (
    <header>
      <div className="logo">
          <img src="static/img/logo.png" alt="Logo" />
      </div>
    </header>
  );
}

export default Header

Since class is a keyword in JavaScript, we can't use the traditional css class attribute in JSX.

Instead, we use className which behaves as you would expect.


this.props

Props allow data to flow from parent components into their children.

Children should NEVER make changes to props.

What if we had both a black and white and color version of our logo Logo component.

function Logo() {
  const imageUrl = this.props.isColor ?
      '/images/logo-color.png' :
      '/images/logo-bw.png';
  return (
    <div className="logo">
      <img src={imageUrl} alt="Logo" />
    </div>
  );
}

export default Logo

Now, when someone wants to use the logo they can just set the isColor property to true or false.


Of course, we could pass true instead.

function Header() {
  return (
    <header>
      <Logo isColor={true} />
    </header>
  );
}

export default Header

If we include the isColor attribute with no value, React will assign it as being true.

This is equivalent to the above example:

function Header() {
  return (
    <header>
      <Logo isColor />
    </header>
  );
}

export default Header

Importing CSS

We can write small, focused css files that live beside our components.

By importing these css files, they'll be bundled up and included in our application as a single css file.


JSX and Separation of Concerns

JSX usually turns heads when people first see it. It's been steadily beat into everyone's head that HTML, CSS, and JS are separate things that each belong in their own file. In JSX it doesn't exactly work that way. But you can still pay attention to separation of concerns.

Imagine if we were adding a CustomerTestimonial widget to an application.

  • index.html: Modify to add some HTML that structures the Customer Testimonial.
  • index.css: Modify the CSS to add some styles for the Customer Testimonial.
  • index.js: Modify the JS to add behavior to the Customer Testimonial (maybe)

Is that really a separation of concerns, though?

If we wanted to add CustomerTestimonial to another page on our app, how would we go about it?

Perhaps we don't have as great a separation of concerns as we thought.


Making Things Modular

In React, we might create a Component that represents a customer testimonial widget like so:

import React from 'react';
import './CustomerTestimonial.css';

function CustomerTestimonial() {
  const defaultImageUrl = '/img/default-customer-image.png';
  const { quote, name, company, imageUrl } = this.props;
  return (
    <div className="testimonial">
      <img src={imageUrl || defaultImageUrl}
        alt="Customer"
      />
      <div className="quote">
        <p>{quote}</p>
        <span className="name">{name}</span>
        <span className="company">{company}</span>
      </div>
    </div>
  );
}

export default CustomerTestimonial;

Using the CustomerTestimonial

We can use this component anywhere we want in our application by simply importing it and using it.

import React from "react";
import CustomerTestimonial from './CustomerTestimonial';

function App() {
  return (
    <CustomerTestimonial
      imageUrl="/img/foo.jpg"
      quote="Totally not bad."
      name="Chad McChad"
      company="Chad's Light Bulbs, Inc" />
  );
}

export default App;

First, we import the component.

Next we reference the component as if it were an HTML component inside JSX.

We can even pass data into our component via it's props

Encapsulation

With a single line of code,

import CustomerTestimonial from './CustomerTestimonial';

We can import that component anywhere we need it, and we'll get everything that the component needs to do it's job.

That's pretty awesome.


Conclusion

Components are at the heart of absolutely every React application you will ever write. It's also slowly creeping in as the default method of organization in many frameworks and even in the DOM API with Web Components. So getting comfortable with this ecosystem is going to pay off in the long run for building web applications.