Revisions
  • December 10th, 2019 - Componentized navigation

Pre-requisites

TL;DR

Checkout the complete solution via GitHub. Don't forget though, you need a MeshyDB account to make this project run–don't panic, it's free!

Creating a React App

Before we begin creating our user registration form, we need to create a new app and install React.

Using Node Package Manager (NPM) you can create a basic React app using our quick start. The quickstart gives you a fully working React app that will be the foundation for this example. To install the quick-start go to your package manager console or terminal and run the following command:

npx @meshydb/react-shell my-app

The npx command will create a working application in the “my-app” directory.

Running Your React App

Once you’ve successfully installed the starter shell it will prompt you to run two commands:

cd my-app
npm start

The npm start command will open the React app in a new browser automatically. If it doesn’t, check your console, it should contain the local URL to run the app.

If you've done everything correctly you should see the React app home page with a giant red warning—don't worry the next step will take care of this.

Initializing the Backend

For this example, we are using the MeshyDB API as the backend. This means all our data will be saved and loaded from MeshyDB.

Before we begin we will need to configure our application to use MeshyDB. To do this, you will need to set two configuration values in the App.js file, account & publicKey. These values need to be changed to reflect your specific account name and public key. If you are not sure how to get either of these values please check out our docs.

src/App.js
const account = '<!-- your account name -->';
const publicKey = '<!-- your public key -->';

If you did everything correctly the red warning should go away—congratz you have successfully configured your app. If not, make sure to follow the instructions on the screen.

Creating the Component

Now that we have a working app we can begin creating our registration form. In React, forms are represented as JavaScript. For this example, we will create a new JavaScript file called src/RegisterForm.js. This file will represent all the UI and logic for our user registration form. To start with, we will add all the necessary parts of a React component including the constructor, state object, event handlers and the render method. We're going to leave most of this blank at the moment and return to it later on.

src/RegisterForm.js (new file)
import React from 'react' 
import { MeshyClient } from "@meshydb/sdk"; 
import Navigation from './Navigation';

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

        this.state = 
        {
            success: '',
            message: ''
        };
        
        this.handleChange = this.handleChange.bind(this);
        this.handleArrayChange = this.handleArrayChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    } 

    handleChange(event)
    {
    }

    handleArrayChange(event)
    {
    }
    
    handleSubmit(event) 
    {
    }

    render()
    { 
        return ( 
            <div> 
                <Navigation />
                <h1>User Registration</h1> 
                <p>
                    Please fill in all the required fields to create a new user account.
                </p>
                {this.state.success === false &&
                <p className="alert alert-danger" role="alert">
                    {this.state.message}
                </p>}
                {this.state.success === true &&
                <p className="alert alert-success" role="alert">
                    User successfully registered
                </p>}
                {!this.state.success &&
                <form onSubmit={this.handleSubmit}>
                </form>}
            </div> 
        ); 
    } 
 } 

export default RegisterForm;

Integrating the Component

Now that we have a new component, we need to transition over to our main src/App.js file so that we can tell the system how and when to load the component.

Importing the Component

By importing our new component, we are allowing the app to reference and use the new form we created.

src/App.js
import RegisterForm from './RegisterForm';

Adding a Route

Now that we have our component registered on this page, we can tell the page when to render the component. This is done with the <Route> component using a path parameter. When the application detects a specific path, it will render whatever child elements exist under the route element. In this example we need to add a new route with a path of “/register” and include our new RegisterForm component as a child element.

Please note, for convenience we are using a 3rd party React-router-dom node package to configure the routing. Don’t worry, its already installed in the starter app. If you are interested in learning more about this package you can checkout their docs.

src/App.js
<Route path="/register"> 
    <RegisterForm />
</Route> 

Adding Navigation

Now that we have our route registered, we need to make it easy for users to get to it. In this example we are going to add a link to the header navigation called “Register” that will take users to our “/register” route.

Please note, for convenience we are using a 3rd party React-bootstrap node package to buildout this navigation. Don’t worry, its already installed in the starter app.

src/Navigation.js
<Nav.Link href="/register">Register</Nav.Link>

Your application should now have a new navigation item that you can click on to load the new registration form.

Building out the Component

Now that we have a component, routing and navigation, we can begin building out the registration form.

Defining State

React uses state to determine when the component’s UI should refresh. This state is managed using a specific property defined in the constructor of the component. Since we want to collect data from the user for the purpose of registration, this state variable is a great place to store our user registration model.

Since we are using the MeshyDB API to create users, we want to try to align the React state with what the API is expecting. This will save time and simplify the codebase. For information on what fields are require or what additional fields can be set during user registration please see our docs.

src/RegisterForm.js
//constructor
this.state =  
{ 
    username: '', 
    firstName: '',
    lastName: '', 
    newPassword: '',
    phoneNumber: '',
    securityQuestions: 
    [ 
        { 
            question: 'What was your best friends name?', 
            answer: '' 
        }, 
        { 
            question: 'What was the name of your first pet?', 
            answer: '' 
        } 
    ], 
    success: null, 
    message: '' 
};

Building Out The Form

Now that our state object is defined, we can build out the form to collect all the necessary information from the user. Using some basic HTML5 and Bootstrap we can create a pretty simple but effective UI.

Note: We are using HTML5 validators to make sure all required fields contain values. These validators are very simple in nature and require a browser that supports HTML5. You may want to use a 3rd party library to enhance validation and increase browser support.

src/RegisterForm.js
{!this.state.success &&
<form onSubmit={this.handleSubmit}>
    <div className="form-group">
        <label>Username</label>
        <input type="text" className="form-control" placeholder="Username" name="username" required onChange={this.handleChange} />
    </div>
    <div className="form-group">
        <label>Password</label>
        <input type="password" className="form-control" placeholder="Password" name="newPassword" required onChange={this.handleChange} />
    </div>
    <div className="form-group">
        <label>First Name</label>
        <input type="text" className="form-control" placeholder="First Name" name="firstName" onChange={this.handleChange} />
    </div>
    <div className="form-group">
        <label>Last Name</label>
        <input type="text" className="form-control" placeholder="Last Name" name="lastName" onChange={this.handleChange} />
    </div>
    <div className="form-group">
        <label>Phone Number</label>
        <input type="text" className="form-control" placeholder="Phone Number" name="phoneNumber" onChange={this.handleChange} />
    </div>
    {this.state.securityQuestions.map((item, index) => (
    <div className="form-group" key={index}>
        <label>{item.question}</label>
        <input type="text" className="form-control" data-index={index} placeholder="Answer" required onChange={this.handleArrayChange} />
    </div>
    ))}
    <button type="submit" className="btn btn-primary">Submit</button>
</form>}

Maintaining State

Unlike other 2-way data binding libraries (such as angular or knockout), React requires custom event handlers to maintain object state. In this example, we will use a generic event handler for state management of basic inputs as well as a more complicated event handler for our security questions array, unfortunately, arrays are a bit more difficult to maintain state on.

Note: this.setState() is a predefined React function used to update the this.state variable. This function expects an object containing the property name as string or a parametrized lookup (using [ ] brackets) along with the new value. If you decide to change the state variable manually React will not know to refresh the UI. If somethings not working correctly try checking your console for any errors. React will tell you when you are modifying state incorrectly.

src/RegisterForm.js
handleChange(event) 
{
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({ [name]: value });

    return true;
}

handleArrayChange(event)
{
    const target = event.target;
    const value = target.value;
    const index = target.dataset.index;

    var updated = this.state.securityQuestions;

    updated[index].answer = value;

    this.setState({ "securityQuestions" : updated });

    return true;
}

Saving Data

Now that our state is being properly managed, we can submit entire state object to the MeshyDB API register endpoint. To do this we need to create and wire-up an event handler for form submission. The event handler will call the registerUser function of the MeshyClient.

The API will take care of all server-side validation. If for whatever reason there is an error, we display the error message to the end-user using the message state variable.

Note: in order to stop the page from doing a post, we need to add event.preventDefault(); at the end of the function.

src/RegisterForm.js
handleSubmit(event) 
{
    MeshyClient.registerUser(this.state).then(_ => {
        this.setState({ "success" : true });
    }).catch(e=>{
        this.setState({ "message" : e.response.message });
        this.setState({ "success" : false });
    });

    event.preventDefault();
}

Putting it All Together

And there you have it, a working user registration form built using react and REST API. And the best part is all your data is stored securely in a serverless backend.

To prove this, we will create a user using the form we just made, and then verify it accessing our MeshyDB user management system. Getting to your user management system is as easy as logging in to meshydb.com and clicking on the "users" tab in the left navigation.

What Next?

This blog is the first part of a multi-part series where we will be demonstrating how to create a complete app using React. To continue in the series please click the link below. We suggest subscribing to our blog and following us on twitter for weekly updates.

Part 2 - User Authentication in React