Bootcamp Notes – Day 11 (Mon) – React: Week 4 – More JavaScript for React

More JavaScript for React

 

Welcome to Week 4

Will learn in JavaScript:

  • Ternary Operator
  • Computed Property Names
  • Spread Syntax
  • Regular Expressions

Will also learn about two different ways to use React with forms to gather input from the user. First you will learn about controlled forms and also learn about form validation as well. Then will learn about uncontrolled forms. Will also learn to setup a React Strap Model.

Will also learn about MVC and Flux design architectures as a precursor for learning about Redux, which is a JavaScript state management library commonly used with React.


JavaScript: ES6 Computed Property Names and Spread Syntax

Computed Property Names and the Spread Syntax are both new to JavaScript in ES6. Though they are here in a single lesson and they both involve working with objects, they are two separate concepts. We will first discuss computed property names.

Computed Property Names allows you to pass in variables for use as property names when initializing an object.

Let us look at example in the console.

We will start by declaring a variable myProperty and storing a string inside it. Then we will declare an object myObject and we will give it a property. For the property identifier we use square braces then inside it that variable that we declared earlier and we will give it a value.

Now if we look inside my object you can see that the property identifier was created using  the string stored in my property.

So you can see how computed property names allow you to create objects more dynamically. You will sometimes have some code to create an object that does not know in advance what the property names will be and will create them from variables that are passed to it.

THE SPREAD SYNTAX

The JavaScript spread syntax can be used with both arrays and objects. In both cases it allows you to pull (“spread”) out a copy of what’s inside the array or object. There are various reasons to do this; in this course, it will generally be to create a new array or object. Later we will see how this can be used with Redux.

Let us see some examples in arrays.

Let us say we have two arrays and we want to combine them together into a new array. You can do it like this using the spread syntax, which is these ellipses these sets of three dots. So here what you are seeing is that the items inside of these two arrays get spread out then recombined into a new array by putting square brackets around both of them.

  • Check the content of the vehicles array to see that it contains a copy of all the items from the spread arrays.
  • What you’re seeing is the result of the landVehicles and waterVehicles arrays being spread out, then put back into a new array by the array literal syntax, the square brackets surrounding both spread arrays. It’s as if you took a bunch of items out from two small boxes, then put all of them into a new, bigger box.
  • You can make new arrays from a combination of spread arrays and any other kind of data you can normally store in an array.

And it does not always have to involve two arrays. It could also be an array and a string that you want to add to the array like this example.

You can even spread and recombine multiple arrays along with other types of data. See mixMatch now?

We can use spread syntax with objects and it gives us an easy way to take multiple objects and combine them together.

For our example, let us take object one and object two and out them together in a new array. Check the value of this new object, and you will be able to see that it contains all the same property key-value pairs from objOne and objTwo. And it did this in a non-mutating way — that is, objOne and objTwo’s values have not been changed. The spread syntax (…) extracted the key-value pairs out from each object. Then the object literal syntax (the curly braces) created a brand new object by combining all the extracted key-value pairs into a single object.

What happens if you try to combine two objects that have properties in common? If you now check the value of the objOneAndThreeCombined object, you should see that it contains the properties color, width, and height, and that the color from objThree (“red”) has overwritten the color from objOne.

The reason that the color from objThree carried over to the new object is simply because it was later in the list than objOne.

Now if we do this:

const objThreeAndOneCombined = {...objThree, ...objOne};

Then you should see that this new object has the color property of “blue”, carried over from objOne.

You can also use the spread syntax to create a new object from an existing object, while updating one or more of its properties.

Now we add this:

const objOneUpdatedHeight = {...objOne, height: 300};

 

Here, the key-value pairs from objOne were spread out, then only the height property was updated, then it was all packed back into a new object. If you check the value of objOneUpdatedHeight.height, it should show 300 now.

Codepen Example!

Summary:

  • Computed property names allow you to pass in variables to use for objects’ property names.
  • The spread syntax, used along with the object literal syntax, allows you to spread out the property key-value pairs from an object then create a new object from them. This can help you combine multiple objects to create a new object. You can also use it to create a copy of an existing object while updating specific properties of that object

JavaScript: Ternary Operator

The Ternary Operator is also know as the conditional operator. It’s called ternary meaning three, because it is the only JavaScript to take 3 operands.

The first operand is the condition to be evaluated followed by a ? question mark. The second is an expression to execute if the condition is truthy followed by a colon. The third and final operand is an expression to execute if the condition is falsy.

condition ? expression if truthy : expression if falsy

The itinerary operator is typically used as a shortcut for the if statement.

Let’s look at an example in the console.

Look at an if statement. Let us say that we have a light switch object with a property that keeps track of the light switches on or off state and a method to turn it off or on. This method we are calling flipSwitch will check if the value of this dot switch state is on and if it is it will change the value to off. Otherwise if the switch state is not on, then it will change the switch state to on. That means every time that we run this method, it will change the switch state from on to off or off to on. You can see in out example that the current switch state is on.

If you call the lightswitch.flipSwitch() method: then off

If you call the lightswitch.flipSwitch() method again: back to on

Now let’s try with Ternary Operator. Overwrite the flipSwitch method in the lightswitch object by entering the following into your console

lightswitch.flipSwitch = function() {
    (this.switchState === "on") ? this.switchState = "off" : this.switchState = "on";
};

 

You should see that the flipSwitch() method is working the same as before.

Another example below here:

NOTE: While the ternary operator can be useful and simplify your code, one drawback is that it can also compromise the readability (and the ease of debugging) your code. Consider this before using it every time; for example, a particularly complex section of code may benefit from the use of a clear if/else statement rather than the ternary operator.

Codepen example here!


Regular Expressions Codepen Example


Overview: Controlled Forms

By now you are familiar with forms from HTML. They are the standard way of obtaining input from users whether via input fields, text area fields or selects.

HTML FORMS

  • Obtain input from users via:
  • input elements (with type text, email, date, checkbox, radio, etc)
  • Textarea elements (for multi-line text fields)
  • Select elements(for drop-downs with multiple options)

Controlled forms in React are a way of setting up an HTML form so that the form values are directly tied to the state of the React Component that the form is in. In this approach React reaches in and takes control of the state of your form elements becoming what’s called the single source of truth for the formed state. This way the HTML FORM and React won’t ever conflict with each other on what the true state is. The form gets its true state directly from React. This way that means any changes that the user makes to the form fields will be immediately reflected in the component state. Then the component is easily able to respond to those changes using JavaScript such as by validating the input and showing error messages.

REACT CONTROLLED FORMS

  • Forms values directly tied to the state of the React component that the form is in
  • React controls the form state, no conflicts between HTML form state and React: React is the the “single-form of truth”
  • Any changes to the form fields immediately reflected in component’s state, can easily be responded to with JavaScript (such as form validation, showing error messages, etc)

Exercise: Controlled Forms

ContactComponent.js

import React, { Component } from ‘react’;
import { Breadcrumb, BreadcrumbItem, Button, Form, FormGroup, Label, Input, Col } from ‘reactstrap’;
import { Link } from ‘react-router-dom’;
class Contact extends Component {
    constructor(props) {
        super(props);
        this.state = {
            firstName: ”,
            lastName: ”,
            phoneNum: ”,
            email: ”,
            agree: false,
            contactType: ‘By Phone’,
            feedback: ”
        };
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleInputChange(event) {
        const target = event.target;
        const name = target.name;
        const value = target.type === ‘checkbox’ ? target.checked : target.value;
    
        this.setState({
            [name]: value
        });
    }
    handleSubmit(event) {
        console.log(‘Current state is: ‘ + JSON.stringify(this.state));
        alert(‘Current state is: ‘ + JSON.stringify(this.state));
        event.preventDefault();
    }
    render() {
        return (
            <div className=”container”>
                <div className=”row”>
                    <div className=”col”>
                        <Breadcrumb>
                            <BreadcrumbItem><Link to=”/home”>Home</Link></BreadcrumbItem>
                            <BreadcrumbItem active>Contact Us</BreadcrumbItem>
                        </Breadcrumb>
                        <h2>Contact Us</h2>
                        <hr />
                    </div>
                </div>
                <div className=”row row-content align-items-center”>
                    <div className=”col-sm-4″>
                        <h5>Our Address</h5>
                        <address>
                            1 Nucamp Way<br />
                            Seattle, WA 98001<br />
                            U.S.A.
                        </address>
                    </div>
                    <div className=”col”>
                        <a role=”button” className=”btn btn-link” href=”tel:+12065551234″><i className=”fa fa-phone” /> 1-206-555-1234</a><br />
                        <a role=”button” className=”btn btn-link” href=”mailto:fakeemail@fakeemail.co”><i className=”fa fa-envelope-o” /> campsites@nucamp.co</a>
                    </div>
                </div>
                <div className=”row row-content”>
                    <div className=”col-12″>
                        <h2>Send us your Feedback</h2>
                        <hr />
                    </div>
                    <div className=”col-md-10″>
                        <Form onSubmit={this.handleSubmit}>
                            <FormGroup row>
                                <Label htmlFor=”firstName” md={2}>First Name</Label>
                                <Col md={10}>
                                    <Input type=”text” id=”firstName” name=”firstName”
                                        placeholder=”First Name”
                                        value={this.state.firstName}
                                        onChange={this.handleInputChange} />
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”lastName” md={2}>Last Name</Label>
                                <Col md={10}>
                                    <Input type=”text” id=”lastName” name=”lastName”
                                        placeholder=”Last Name”
                                        value={this.state.lastName}
                                        onChange={this.handleInputChange} />
                                </Col>                        
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”phoneNum” md={2}>Phone</Label>
                                <Col md={10}>
                                    <Input type=”tel” id=”phoneNum” name=”phoneNum”
                                        placeholder=”Phone number”
                                        value={this.state.phoneNum}
                                        onChange={this.handleInputChange} />
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”email” md={2}>Email</Label>
                                <Col md={10}>
                                    <Input type=”email” id=”email” name=”email”
                                        placeholder=”Email”
                                        value={this.state.email}
                                        onChange={this.handleInputChange} />
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Col md={{size: 4, offset: 2}}>
                                    <FormGroup check>
                                        <Label check>
                                            <Input type=”checkbox”
                                                name=”agree”
                                                checked={this.state.agree}
                                                onChange={this.handleInputChange} /> {‘ ‘}
                                            <strong>May we contact you?</strong>
                                        </Label>
                                    </FormGroup>
                                </Col>
                                <Col md={4}>
                                    <Input type=”select” name=”contactType”
                                            value={this.state.contactType}
                                            onChange={this.handleInputChange}>
                                        <option>By Phone</option>
                                        <option>By Email</option>
                                    </Input>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”feedback” md={2}>Your Feedback</Label>
                                <Col md={10}>
                                    <Input type=”textarea” id=”feedback” name=”feedback”
                                        rows=”12″
                                        value={this.state.feedback}
                                        onChange={this.handleInputChange}></Input>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Col md={{size: 10, offset: 2}}>
                                    <Button type=”submit” color=”primary”>
                                        Send Feedback
                                    </Button>
                                </Col>
                            </FormGroup>
                        </Form>
                    </div>
                </div>
            </div>
        );
    }
}
export default Contact;

Exercise: Controlled Form Validation

ContactComponent.js

imporReact, { Component } from ‘react’;
import { Breadcrumb, BreadcrumbItem, Button, Form, FormGroup, Label, Input, Col, FormFeedback } from ‘reactstrap’;
import { Link } from ‘react-router-dom’;
class Contact extends Component {
    constructor(props) {
        super(props);
        this.state = {
            firstName: ”,
            lastName: ”,
            phoneNum: ”,
            email: ”,
            agree: false,
            contactType: ‘By Phone’,
            feedback: ”,
            touched: {
                firstName: false,
                lastName: false,
                phoneNum: false,
                email: false
            }
        };
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    validate(firstName, lastName, phoneNum, email) {
        const errors = {
            firstName: ”,
            lastName: ”,
            phoneNum: ”,
            email: ”
        };
        if (this.state.touched.firstName) {
            if (firstName.length < 2) {
                errors.firstName = ‘First name must be at least 2 characters.’;
            } else if (firstName.length > 15) {
                errors.firstName = ‘First name must be 15 or less characters.’;
            }
        }
        if (this.state.touched.lastName) {
            if (lastName.length < 2) {
                errors.lastName = ‘Last name must be at least 2 characters.’;
            } else if (lastName.length > 15) {
                errors.lastName = ‘Last name must be 15 or less characters.’;
            }
        }
        const reg = /^\d+$/;
        if (this.state.touched.phoneNum && !reg.test(phoneNum)) {
            errors.phoneNum = ‘The phone number should contain only numbers.’;
        }
        if (this.state.touched.email && !email.includes(‘@’)) {
            errors.email = ‘Email should contain a @’;
        }
        return errors;
    }
    handleBlur = (field) => () => {
        this.setState({
            touched: {…this.state.touched, [field]: true}
        });
    }
    handleInputChange(event) {
        const target = event.target;
        const name = target.name;
        const value = target.type === ‘checkbox’ ? target.checked : target.value;
    
        this.setState({
            [name]: value
        });
    }
    handleSubmit(event) {
        console.log(‘Current state is: ‘ + JSON.stringify(this.state));
        alert(‘Current state is: ‘ + JSON.stringify(this.state));
        event.preventDefault();
    }
    render() {
        const errors = this.validate(this.state.firstName, this.state.lastName, this.state.phoneNum, this.state.email);    
        return (
            <div className=”container”>
                <div className=”row”>
                    <div className=”col”>
                        <Breadcrumb>
                            <BreadcrumbItem><Link to=”/home”>Home</Link></BreadcrumbItem>
                            <BreadcrumbItem active>Contact Us</BreadcrumbItem>
                        </Breadcrumb>
                        <h2>Contact Us</h2>
                        <hr />
                    </div>
                </div>
                <div className=”row row-content align-items-center”>
                    <div className=”col-sm-4″>
                        <h5>Our Address</h5>
                        <address>
                            1 Nucamp Way<br />
                            Seattle, WA 98001<br />
                            U.S.A.
                        </address>
                    </div>
                    <div className=”col”>
                        <a role=”button” className=”btn btn-link” href=”tel:+12065551234″><i className=”fa fa-phone” /> 1-206-555-1234</a><br />
                        <a role=”button” className=”btn btn-link” href=”mailto:fakeemail@fakeemail.co”><i className=”fa fa-envelope-o” /> campsites@nucamp.co</a>
                    </div>
                </div>
                <div className=”row row-content”>
                    <div className=”col-12″>
                        <h2>Send us your Feedback</h2>
                        <hr />
                    </div>
                    <div className=”col-md-10″>
                        <Form onSubmit={this.handleSubmit}>
                            <FormGroup row>
                                <Label htmlFor=”firstName” md={2}>First Name</Label>
                                <Col md={10}>
                                    <Input type=”text” id=”firstName” name=”firstName”
                                        placeholder=”First Name”
                                        value={this.state.firstName}
                                        invalid={errors.firstName}
                                        onBlur={this.handleBlur(“firstName”)}
                                        onChange={this.handleInputChange} />
                                    <FormFeedback>{errors.firstName}</FormFeedback>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”lastName” md={2}>Last Name</Label>
                                <Col md={10}>
                                    <Input type=”text” id=”lastName” name=”lastName”
                                        placeholder=”Last Name”
                                        value={this.state.lastName}
                                        invalid={errors.lastName}
                                        onBlur={this.handleBlur(“lastName”)}
                                        onChange={this.handleInputChange} />
                                    <FormFeedback>{errors.lastName}</FormFeedback>
                                </Col>                        
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”phoneNum” md={2}>Phone</Label>
                                <Col md={10}>
                                    <Input type=”tel” id=”phoneNum” name=”phoneNum”
                                        placeholder=”Phone number”
                                        value={this.state.phoneNum}
                                        invalid={errors.phoneNum}
                                        onBlur={this.handleBlur(“phoneNum”)}
                                        onChange={this.handleInputChange} />
                                    <FormFeedback>{errors.phoneNum}</FormFeedback>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”email” md={2}>Email</Label>
                                <Col md={10}>
                                    <Input type=”email” id=”email” name=”email”
                                        placeholder=”Email”
                                        value={this.state.email}
                                        invalid={errors.email}
                                        onBlur={this.handleBlur(“email”)}
                                        onChange={this.handleInputChange} />
                                    <FormFeedback>{errors.email}</FormFeedback>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Col md={{size: 4, offset: 2}}>
                                    <FormGroup check>
                                        <Label check>
                                            <Input type=”checkbox”
                                                name=”agree”
                                                checked={this.state.agree}
                                                onChange={this.handleInputChange} /> {‘ ‘}
                                            <strong>May we contact you?</strong>
                                        </Label>
                                    </FormGroup>
                                </Col>
                                <Col md={4}>
                                    <Input type=”select” name=”contactType”
                                            value={this.state.contactType}
                                            onChange={this.handleInputChange}>
                                        <option>By Phone</option>
                                        <option>By Email</option>
                                    </Input>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Label htmlFor=”feedback” md={2}>Your Feedback</Label>
                                <Col md={10}>
                                    <Input type=”textarea” id=”feedback” name=”feedback”
                                        rows=”12″
                                        value={this.state.feedback}
                                        onChange={this.handleInputChange}></Input>
                                </Col>
                            </FormGroup>
                            <FormGroup row>
                                <Col md={{size: 10, offset: 2}}>
                                    <Button type=”submit” color=”primary”>
                                        Send Feedback
                                    </Button>
                                </Col>
                            </FormGroup>
                        </Form>
                    </div>
                </div>
            </div>
        );
    }
}
export default Contact;

 


Additional Resources: