« Previous Tutorial Next Tutorial »

Now that we can log users in and out, we need to be able to register new ones. This process is similar to the log-in form, just with a few extra bits and pieces. We’re going to cover a lot of code in this tutorial, but most of it should seem pretty familiar by now, so I’m going to get a little more ambitious in terms of how much I throw at you at once. If it gets confusing, leave a comment, and we’ll get you sorted out!

We’re going to do this in sort of a strange way, by starting at the top level, importing a component that doesn’t exist yet, then creating that component, and then doing the same thing again. So start off by opening /src/components/Template.jsx. Below line 7, add the following:

import RegisterPage from './account/RegisterPageContainer';

And below line 18 add this code:

          <Route exact path="/account/register" component={RegisterPage} />

Save this file, and we’re done here. Obviously, we now need to create /src/components/account/RegisterPageContainer.jsx … so do that! This page is almost identical to /src/components/account/LoginPageContainer.jsx, and not terribly long, so I’m going to just give it to you all at once:

import React from 'react';
import { connect } from 'react-redux';

import RegisterPage from './RegisterPage';

export class RegisterPageContainer extends React.Component {
  constructor(props) {
    super(props);

    // bound functions
    this.registerFunction = this.registerFunction.bind(this);
  }

  registerFunction(userData) {
    const { dispatch } = this.props;
    // dispatch(registerUser(userData));
    console.log(userData);
  }

  render() {
    return (
      <div>
        <RegisterPage registerFunction={this.registerFunction} />
      </div>
    );
  }
}

export default connect()(RegisterPageContainer);

As you can see, we import React and Redux, connect our container to Redux so that we can use dispatch, and then write a little function to pass down to the register form that registers a user … or, more accurately for the moment, console logs the incoming user data, because we haven’t actually written any actions or reducers to handle registration. That’ll come in the next tutorial.

Once you’re set here, save the file, and then create a new one in /src/components/account/ called RegisterPage.jsx. This is where we’ll be putting our form fields and stuff. Let’s start with our imports. Here they are:

import React from 'react';
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';

Nothing fancy here. React and some Reactstrap components, the latter of which we’ll use in our render block. Let’s move on to our class:

export default class ProfilePage extends React.Component {
  constructor(props) {
    super(props);

    // bound functions

    // component state
    this.state = {
      email: '',
      firstName: '',
      lastName: '',
      password: '',
      username: '',
    };
  }
  render() {
    return (
      <div className="row justify-content-center">
        <div className="col-10 col-sm-7 col-md-5 col-lg-4">
        </div>
      </div>
    );
  }
}

This, obviously, will create an empty page with nothing in it, which isn’t particularly useful! So let’s fill that page in with form elements. This is a big bunch of code, but it’s just a little introductory text, five input fields, and a button. So between those div tags (lines 22 and 23), add the following:

          <p>
            Want to get started saving your favorite bands to MusicList?
            Create an account!
          </p>
          <Form>
            <FormGroup>
              <Label for="email">Email</Label>
              <Input
                id="email"
                name="email"
                onChange={this.handleInputChange}
                onKeyPress={this.handleKeyPress}
                placeholder="noreply@musiclist.com"
                type="email"
                value={this.state.email}
              />
            </FormGroup>

            <FormGroup>
              <Label for="password">Password</Label>
              <Input
                id="password"
                name="password"
                onChange={this.handleInputChange}
                onKeyPress={this.handleKeyPress}
                placeholder="password"
                type="password"
                value={this.state.password}
              />
              <span>
                We recommend a password service like&nbsp;
                <a href="https://www.lastpass.com/" target="_blank" rel="noopener noreferrer">LastPass</a>
                &nbsp;or <a href="https://1password.com/" target="_blank" rel="noopener noreferrer">1Password</a>
              </span>
            </FormGroup>

            <FormGroup>
              <Label for="username">Username</Label>
              <Input
                id="username"
                name="username"
                onChange={this.handleInputChange}
                onKeyPress={this.handleKeyPress}
                placeholder="CaptainCode"
                type="text"
                value={this.state.username}
              />
            </FormGroup>

            <FormGroup>
              <Label for="firstName">First Name</Label>
              <Input
                id="firstName"
                name="firstName"
                onChange={this.handleInputChange}
                onKeyPress={this.handleKeyPress}
                placeholder="Jamie"
                type="text"
                value={this.state.firstName}
              />
            </FormGroup>

            <FormGroup>
              <Label for="lastName">Last Name</Label>
              <Input
                id="lastName"
                name="lastName"
                onChange={this.handleInputChange}
                onKeyPress={this.handleKeyPress}
                placeholder="Smith"
                type="text"
                value={this.state.lastName}
              />
            </FormGroup>

            <Button color="primary" onClick={this.compileFormData}>Register</Button>
          </Form>

The weirdest thing here is those &amp;nbsp; tags in the span under the password input. We have to do this because we’re breaking the line into multiple chunks. JSX is still JavaScript, and JavaScript doesn’t care about line breaks, so unfortunately unlike with HTML, a linebreak doesn’t necessarily turn into a space. Except sometimes it does! The JSX interpreter is a little weird. So you have to put those &amp;nbsp; tags in those exact places to get the spacing you want.

Now we need some functions. Our handleKeypress function that checks to see if the enter key was pressed will be identical to the one we wrote for LoginPage.jsx, but we’re doing something a little different with handling changes to the form fields. Instead of writing a function for each field, we’re going to write a generic function which will use the target’s id to update values in the state. Note that all of our inputs’ id attributes are identical to the component state values we defined (eg: email, password, etc).

So, here are your three functions. Put this code between your constructor block and your render block:

  // Put everything together and send it up to the register function
  compileFormData() {
    const { registerFunction } = this.props;
    const formData = this.state;
    registerFunction(formData);
  }

  // Handle input changes
  handleInputChange(e) {
    this.setState({ [e.currentTarget.id]: e.target.value });
  }

  // catch enter clicks
  handleKeyPress(target) {
    if (target.charCode === 13) {
      target.preventDefault();
      this.compileFormData();
    }
  }

As always, we’ll need to bind these functions so that they inherit this from the class, so under line 8, add the following code:

    this.compileFormData = this.compileFormData.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleKeyPress = this.handleKeyPress.bind(this);

That’s it! Save the file. We’ve got a little extra time here, so I’m going to show you how to hide the redux dev tools by default. They’re very useful when testing actions, but having the window always open when the page refreshes is a bit much. Open up /src/components/shared/DevTools.jsx and change line 10 from:

    defaultIsVisible

to:

    defaultIsVisible={false}

Save that file and head for a browser. Point it at locahost:3000/account/register and witness the glory of your new register page (and note that the redux dev tools don’t show up until you hit ctrl-h). You can fill in the inputs, and if you have your console open, when you click the button or press enter, you’ll see it console log out the values. Step one is complete. Now we need to submit this to the API and actually register a new user. We’ll do that in the next tutorial. See you there!

« Previous Tutorial Next Tutorial »