Trying to keep the pace.

My last post got me all setup to start creating a web app with React. So let’s make something. ‘Tis the season so I’ll be making a secret santa generator. Let’s take a look at the requirements of the app:

  • Add people as participants. A participant has a name and an email.
  • Display the participants and their recipients.
  • Assign each person a recipient that’s not themselves.
  • Add more participants and reassign recipients.

It’s a very simple app, but one that has familiarized me with much of React’s basics, terminology, and principles. I’ll try my best to explain as I go but I haven’t been doing this much longer than you at this point. I’ll mostly be referring you to links and resources that have helped me.

First, I’ll create my project. In the terminal:

Open the project in your editor of choice. I’m not going to go over every file generated for us. Open up to src/App.js. This is our main application file. If you look in src/index.js, you’ll see that an instance of our App class is mounted to our “root” element.

Back in our App.js file, you’ll notice that there’s one class declared, App, and it extends Component. If all of this syntax is unfamiliar to you in the context of JavaScript, you’ll want to read up on ES2016. Inside App is a single function, render(). This is where we return the functional and class components that make up our application. Looking at what App is rendering:

This code may look like simple HTML but don’t be fooled, it’s actually JSX. All of this HTML-looking code will be transpiled into regular ol’ JavaScript. We’re not going to need most of this code so delete everything except the root <div>.

Identifying Components

I’m just translating our requirements into components. Use your judgement with how granular you want to get in defining components, which is difficult when first learning. Trust me. I struggled with even this simple app. My only advice so far is to start broad and only use more granularity out of necessity and draw pictures. I identified the following components but yours can absolutely have more or less:

  • A form so we can add participants’ names and emails.
  • Two lists: one to display participants and another for recipients.
  • A button to trigger our secret santa algorithm, which will assign each participant a person to buy a gift for.

Mind the State

Just because each component needs to know about some part of the state doesn’t mean each component needs a state of its own. The state and logic to modify the state should live in common ancestor to all our identified components. The simple nature of our app means that the App itself will do fine. I expect there’s cases when more than stateful component is needed, and I could probably stretch this example further to show that, but I’m not going to overcomplicate things for the time being.

So what properties should be in our state? Looking back at the list of requirements, we only need to keep track of participants and the people they’re assigned. Each participant will be a simple object with name and email properties. To initialize state, write a constructor and set the state:

We need to call super to initialize the context and we pass any props provided to the parent. Then we set our state to an object with a participants and assignments property, both arrays.

Dumb Components…

Choosing to keep our state in App has the effect of simplifying components down to stateless functional components. These are simply components used to display information from the state, which are received as props. Let’s declare the list component we identified earlier:

Stateless function components are just functions (in this case an arrow function) that receive a props argument and return what should be rendered. If the argument list looks funny, it’s because I’m using the fancy destructuring syntax. The following is equal to the above but uses an extra line for explicit assignment:

Since items is an array, we use the map function to transform each person into JSX. We can wrap the return value in curly braces so that it is evaluated and placed between within our <ul> tags.

To utilize <List>, return to our App‘s render function. We have two lists we’d like to display, the participants list and the assignments list. But we only want to display the assignments list after we’ve actually assigned people so we’ll add a conditional in the render function.

Alternatively, we could add the conditional logic in the return statement:

Taking advantage of the logical-AND operator’s short-circuit functionality, we can check if the assignments array has length greater than zero (which is important because this.state.assignments.length will render zero as a string if we didn’t use the comparison operator) and if it’s true, the second part of the logical-AND expression will execute rendering our list. This works because boolean values true and false are ignored by JSX.

Inverse Data Flow

Our <List> component is awesome, there’s no denying it, however it’s empty inside… no substance. In this section we’ll be creating our form component to allow people to be added. Remember, people in our app are a name and an email so we just need two text inputs with placeholder text for each. Lastly, we’ll need the all important submit button, which can also be triggered by pressing the enter key since we’re creating a form.

How do we get the values from the text fields on form submission? We don’t want the page to reload either so we’ll have to stop the default behavior of a form submit. Lastly, we need to pass the data back to App and update the state.

The first question admittedly took me a while to figure out. I’m not really sure why. The answer was staring me in the face in the React docs. Read the page I linked to as it explains how the ref attribute works.

Waiting… Now look at our updated <Form>.

We added variables to hold our inputs and in the ref attribute added a function that accepts the DOM element as an argument and assigns it to the corresponding variable. Next, let’s handle the form submission.

The onFormSubmit function is set as the <Form>’s onSubmit handler. It receives an event as its argument, e, and we use it to stop the form from actually submitting and causing our page to reload by calling preventDefault(). We’ll get back to the next line in a bit. The following lines clear the values of the text inputs and refocuses the nameField so that the user can start typing the next participant’s name.

The one we skipped is a function that was passed in as a prop. Again, we used destructuring here. The onSubmitHandler accepts the text input values as arguments. Hopefully you can guess what this function does and where it might live. If you said, it adds a participant and it’s a function of the App class, then you’re probably too smart to be reading my website and I kindly ask you to feature me on your probably much cooler website! I tried. Back to coding.

In our App  class, create the following member function:

It accepts name and email just like the handler we have to pass into <Form>. It then updates the state using a callback. Now we just need to update our App‘s render call to display the form and pass the function down to our component.

One last little gotchya. We have to bind the context to our member functions or else this will be undefined in our class’ functions. From the React docs:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

It’s an easy fix. In the constructor we write:

Clicking the “Add” button will now add a new person to our participant array in our state. A state update will cause the render function to fire again and display our newly added person.

Whew! Coding is hard enough but explaining it not only to myself but to (possibly) others is a challenge! And this is only part 1. In part 2, we’ll finish up the functionality and pretty it up. I also want to delve deeper into unit testing using Jest and Enzyme. Until then, look over the resources below and all the other links sprinkled throughout the article.

Until next time!

  • egghead.io’s React Fundamentals: egghead.io has a mix of free and paid courses. This one is free. It moves quickly but is a crash course in the basics.
  • kirupa.com’s series of React tutorials: this was my first introduction to React. I used to go to his site for ActionScript 3 help. Then I got an email one day saying he’d solved all the mysteries of React. My first thought was, “Wut?” His explanations and writing style are great for beginners. The only downside is that his examples don’t use ES2016.
  • Official React Docs: Obviously.