« Previous Tutorial Next Tutorial »

Today’s tutorial is short and, I think, fun. We’re going to use all the stuff we did in the last few tutorials to make some nice aesthetic tweaks to our site, while also continuing to demonstrate how passing down values as props works.

Let’s jump right in by turning our incrementing/decrementing number into an actual loading spinner. We’re going to do this entirely with CSS and no images, but first, we need some HTML. Open up /src/components/Template.jsx. Find our current props.progress display on line 14:

        <p>{props.progress}</p>

and nuke the entire thing from orbit like it was an alien-infested mining colony. Next up, just below line 18, our &lt;/section&gt; tag, add this code:

        <div className="loader-wrapper" style={props.progress > 0 ? { display: 'block' } : { display: 'none' }}>
          <div className="loader-box">
            <div className="loader">Loading...</div>
          </div>
        </div>

As you can see, we’re now checking to see if the progress prop is anything above zero, and displaying or hiding our spinner based on that. This works automatically because in React, active components re-render when their props change. Since our Template receives progress as a prop, it will re-render whenever the value changes. This is one of the best things about React.

Also note that inline styles in React require curly braces that contain an object. This is for consistency with DOM properties in JavaScript and also helps with security. You can learn more about it in React’s documentation, if you’d like.

Save this file. We’ll be coming back to it in a bit, but for now let’s add some CSS. Open up /src/css/musiclist.scss and get ready to add a whole crapload of code. We’re borrowing our CSS, with a few slight modifications, from Luke Haas, who created a bunch of css-only spinners. I’ll link the page in the YouTube description.

Here’s all the code. I’m spamming it at you all at once because it’s mostly copy-paste.

/ Spinner /
.loader-wrapper {
  overflow: hidden;
  position: fixed;
  top: 10px;
  z-index: 90;
  width: 100%;
  text-align: center;
  display: none;

  .loader-box {
    width: 40px;
    height: 40px;
    overflow: hidden;
    margin: 0 auto;

    .loader,
    .loader:after {
      border-radius: 50%;
      width: 10em;
      height: 10em;
    }

    .loader {
      margin: 0;
      font-size: 3.5px;
      position: relative;
      text-indent: -9999em;
      border-top: 1.1em solid rgba(155,155,155, 0.2);
      border-right: 1.1em solid rgba(155,155,155, 0.2);
      border-bottom: 1.1em solid rgba(155,155,155, 0.2);
      border-left: 1.1em solid #999;
      -webkit-transform: translateZ(0);
      -ms-transform: translateZ(0);
      transform: translateZ(0);
      -webkit-animation: load8 1.1s infinite linear;
      animation: load8 1.1s infinite linear;
    }

    @-webkit-keyframes load8 {
      0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
      }
    }

    @keyframes load8 {
      0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
      }
    }
  } / loader-box /
} / loader-wrapper /

That’s a lot, but it’ll look great, trust me. Actually, you don’t have to trust me, because you can see for yourself. Save this file, and if your hot module loader was running, you should see that the progress number has disappeared from your pages. You’ll need to do a hard-refresh to get the new CSS, though. Once you’ve done so, hit your homepage and click the increment / decrement buttons to prove that the spinner shows up when progress is greater than zero, and disappears when progress returns to zero.

Cool. Let’s make our header swap between a “log in” link and some “Welcome, [firstName]” text. Open up /src/components/TemplateContainer.jsx. We’re going to need to map our authentication state to props, so under line 13, add the following:

    authentication: state.authentication,

and then under line 5, add this code:

  const { authentication, progress } = props;

Now that we have more than one prop to access, it makes more sense to do it this way, using variable destructing, rather than always using props.valueName in the code below. This means we can change line 8 from:

    <Template progress={props.progress} />

to:

    <Template progress={progress} authentication={authentication} />

That’s it. We’re just passing authentication on down to our Template.

Save the file, and then head back to /src/components/Template.jsx. We’re just going to continue bouncing our authentication prop on down the chain to the header, where we’ll handle display. Let’s do some variable destructuring here, too. Below line 9, add this code:

  const { authentication, progress } = props;

Then change line 14 from:

        <Header username="anonymous" />

to:

        <Header username="anonymous" authentication={authentication} />

And line 20 from:

        <div className="loader-wrapper" style={props.progress > 0 ? { display: 'block' } : { display: 'none' }}>

to:

        <div className="loader-wrapper" style={progress > 0 ? { display: 'block' } : { display: 'none' }}>

We’re good here, so save the file. Now that we’re passing the authentication block all the way down to the header, let’s use it. Open up /src/components/shared/Header.jsx. First we’re going to create two helper functions. These guys don’t need access to this from our class, so they can just be free-standing functions that take an argument (or don’t). Below line 4, add a padding line and then add this code:

const renderLogin = () => <NavLink tag={Link} to="/account/login">Log In</NavLink>;
const renderGreeting = name => <span>Welcome, {name}</span>;

Both of these are using ES6 explicit returns, which we’ve talked about a few times. If you use an arrow function with no brackets on a single line, it assumes you’re returning whatever comes after the arrow, which in this case is JSX code.

Your class should start on line 8. To it, we need to add some variable destructing just under the render() method, which with my spacing is line 25. So, just below it, add this code:

    const { isLoggedIn, firstName } = this.props.authentication;

Now let’s change line 35 from:

                <NavLink tag={Link} to="/account/login">Log In</NavLink>

to:

                { isLoggedIn ? renderGreeting(firstName) : renderLogin() }

We’re checking the value of authentication.isLoggedIn and, if it’s truthy, rendering a greeting. Otherwise we’re rendering the log in link.

We’re good to go. Save this file and head for a browser. I recommend a full refresh here not so much because you need it for React to work (all of this stuff should be child’s play for your hot reloader) but because currently hard-refreshing nukes our logged in user value from the Store. That’s a problem that we’re going to fix soon, but for right now it’s useful since we don’t yet have a “log out” link.

If you’re logged out and on the homepage, and have hidden your developer tools with ctrl-h, you should see your log in link. Click it, and perform a successful login. You’ll see two things happen. First, the spinner will probably flash on screen for a split second. Second, once you’re forwarded back to the home page, you should see your welcome text using whatever value you entered for firstName when you created your admin user.

Pretty cool, right? This is the core of how the React/Redux data flow works. In future tutorials we’ll be expanding on this a lot, but the core mechanic will be mostly the same.

Next up, we’ll tie into the log-out function we wrote for our API, and then tackle that problem where the user appears to be logged out whenever they hard-refresh. Catch you then!

« Previous Tutorial Next Tutorial »