Basic

An open-source Facebook project.

React/ReactJS was invented to manipulate website DOM faster than Javascript Core, using a virtual DOM model.
React/ReactJS is a Javascript library.
React/ReactJS can run on the front or back end.

React Native was built after React, as a platform for building native apps using Javascript. (As opposed to using Java on Android and Objective-C on iPhone)
React Native is built on ReactJS.
To run a React Native app, you'll need XCode (Mac) or Android Studio (Android).
React Native does not use HTML to render the app; instead it uses native UI components.

Prerequisites: Javascript, HTML
Babel

Babel is a Javascript compiler. It can convert markup and programming languages into Javascript.

ReactJS uses Babel to convert JSX into Javascript.

Using in-browser compiler, which will be slow for your clients:

    <html>
        <head>
            <meta charset="UTF-8">

            <!-- Load React. -->
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
            <!-- If using JSX -->
            <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
        </head>
        <body>
            <div id="root"></div>
        </body>
    </html>

    <script type='text/babel'>
        ReactDOM.render(
            <h1>Hello, world!</h1>,
            document.getElementById('root')
        );
    </script>

Preprocessor

Compile JSX to Javascript before serving pages to your clients.

1) Install Node.js on your computer.
2) In terminal: npm init -y
3) In terminal: npm install babel-cli@6 babel-preset-react-app@3
4) In terminal: npx babel --watch source --out-dir . --presets react-app/prod

Step (4) starts a "watcher" application.
Now when you create a file with JSX in it in the "source" directory, it will be automatically processed into a plain Javascript file, with the same file name, in the output directory.

JSX

JSX stands for Javascript XML. It is a language extension for Javascript.

JSX is an easy-to-read syntax that is compiled into "React.createElement(component, properties, ...children)" commands.

JSX expressions produce React elements.

The aim is to keep tightly coupled business logic and display logic together, while separating the concerns of different components.

So this:

    <MyButton color="blue" shadowSize={2}>
        Click Me
    </MyButton>
Will be compiled into this:

React.createElement(
    MyButton,
    {color: 'blue', shadowSize: 2},
    'Click Me'
)
You can write the "React.createElement" commands directly, if you prefer them.

[You can test JSX in this Babel compiler]

Elements

JSX does not use quotes (" or ') around HTML elements.

var element = <h1>Hello World!</h1>

Expressions

Expressions inside curly braces { } will be interpreted as Javascript in the current context.


<div id="myDiv">Hello Someone</div>

<script type="text/babel">
    var name = 'John Doe';
    ReactDOM.render(
        <h1>Hello {name}</h1>,
        document.getElementById('myDiv')
    );
</script> 

Do not use quotes (" or ') around curly braces. If the result of the expression is a string, it will be stored correctly.

Attributes

JSX uses camel-case attributes names.
JSX avoids using Javascript reserved words as attribute names.

HTML attribute "class" => JSX "className"
HTML attributes "tabindex" => JSX "tabIndex"

Types

Capitalized tag names refer to React components.

Ex: "<Foo />" refers to an in-scope variable named "Foo".

Injection

It is safe to insert user-data directly into JSX, because React automatically escapes all special characters.
Getting Started

You can use a little React in your Javascript, or a lot.

Loading ReactJS into webpage:

    <!DOCTYPE html>
    <html lang="en">

        <!-- Load React API -->
        <script src= "https://unpkg.com/react@16/umd/react.production.min.js"></script>
        <!-- Load React DOM-->
        <script src= "https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
        <!-- Load Babel Compiler -->
        <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

        <body>

            <script type="text/babel">
                // JSX Babel code goes here
            </script>

        </body>
    </html> 

For *.js pages:

import React from 'react';

Like Button

"Like" Button example.

likeButton.html

    <html>
        <head>
            <meta charset="UTF-8">

            <!-- Load React. -->
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

        </head>
        <body>
            <div id="like_button_container"></div>

            <!-- Load our React component. -->
            <script src="likeButton.js"></script>
        </body>
    </html>
The "likeButton.js" must be loaded at the end of the "body" element.
If you load it in the "head" element, before the "div" is defined, you'll get a "target container is not a dom element" error.

likeButton.js (contains React component "LikeButton")

'use strict';

const e = React.createElement;

class LikeButton extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.state = { liked: false };
    }

    render() 
    {
        if (this.state.liked) 
        {
            return 'You liked this.';
        }

        return e(
            'button',
            { onClick: () => this.setState({ liked: true }) },
            'Like'
        );
    }
}

const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);
React Native

Setup Environment

For Windows:
[Setup React Native on Windows]

1) Install Node.js. This includes "npm".
[Download Node.js]

2) Install JDK (Java SE Development Kit)
[Download JDK]

3) Install Android Studio
[Download Android Studio]

4a) Add Java SDK path to Windows Environment Variables
- Add New
- Name: JAVA_HOME (this name is expected)
- Path: C:\Program Files\Java\jdk-11.0.2 (or whatever your path is)

4b) Add Android Studio path to Windows Environment Variables
- Add New
- Name: ANDROID_HOME (this name is expected)
- Path: C:\Program Files\Android\Android Studio (or whatever your path is)

5) Configure an Android Virtual Device
a) Open Android Studio
b) Start a new project (maybe not this? create react native project in step 6)
c) Create an Android Virtual Device: Tools menu > ADV Manager > Create
-- the ADV Manager option will not appear until the application is fully loaded
-- you'll need to create a virtual device profile for every platform your application will run on
d) Boot the ADV
-- click the "Launch" arrow

6) Command Prompt
a) Open command prompt
b) Navigate to project folder
c) Install React Native globally

npm install -g react-native-cli
d) Create new react native project

react-native init MyProject
This will create a folder "MyProject" containing all the files for a new react native application.

7) Configure build.gradle
Change "android/app/build.gradle" file to use the correct version number of Android Studio SDK
??????????

Continue from here:
http://www.ntu.edu.sg/home/ehchua/programming/android/android_howto.html


To see the Android SDK version you have installed:
- Open Android Studio
- Tools menu > Android SDK
- select Appearance & Behavior > System Settings > Android SDK
You'll see a list of available SDKs, and which are installed.


8) Start application
a) Navigate into project folder in Command Prompt
b) Run application

react-native run-android
Wait awhiiiiiiile for Gradle to start up.
c) Start the packager

react-native start

TODO: complete these steps to test that they work
Elements

React elements are returned by "React.createElement" statements.

React elements are plain Javascript objects.

React DOM handles keeping the HTML DOM up to date with the React elements.


const element = (
    <h1 className="greeting">
        Hello, world!
    </h1>
);
//becomes
const element = React.createElement(
    'h1',
    {className: 'greeting'},
    'Hello, world!'
);
//becomes something like
const element = {
    type: 'h1',
    props: {
        className: 'greeting',
        children: 'Hello, world!'
    }
};

Immutable

React elements are immutable.

For each change to the DOM, you'll need to create a new React element and render it.

This update process is greatly simplified by using React components.
DOM Render

Render React elements to the HTML DOM.

Example:

    <div id="id01">Hello World!</div>

    <script type="text/babel">
        ReactDOM.render(
            <h1>Hello React!</h1>,
            document.getElementById('id01')
        );
    </script> 

React DOM compares the React element(s) with the current state of the HTML DOM. The minimum of necessary changes are made to update the HTML DOM.

The idea is to specify how the UI should look at each moment in time, instead of focusing on the exact series of changes being made.
Components

React components are independent, reusable, auto-updating pieces of a web application.

React components are structured as Javascript functions that accept properties and return React elements.

Naming

Always start component names with a capital letter.

JSX will interpret capitalized tag names as references to components.

Function Components

Function components are the simplest examples.


function Welcome(props) 
{
    return <h1>Hello, {props.name}</h1>;
}

Usage:

//component
function Welcome(props) 
{
    return <h1>Hello, {props.name}</h1>;
}
//element references component
//all attributes are passed to "Welcome()" as "props"
const element = <Welcome name="Sara" />;
//render
ReactDOM.render(
    element,
    document.getElementById('root')
);

If your component returns "null" instead of a React element, nothing will be rendered for it. This can be used to hide components.

ES6 Class Components


class Welcome extends React.Component 
{
    render() 
    {
        return <h1>Hello, {this.props.name}</h1>;
    }
}

Class components have local state.


class Clock extends React.Component 
{
    constructor(props)
    {
        super(props);
        this.state = {date: new Date()};
    }
    
    //a Life-Cycle Method
    //claim memory once, when the React element is first rendered to the DOM
    componentDidMount()
    {
        this.timerID = setInterval(() => this.tick(), 1000);
    }
    
    //a Life-Cycle Method
    //like Dispose - free up memory when the React element is fully removed from the DOM
    componentDidUnmount()
    {
        clearInterval(this.timerID);
    }
    
    tick() 
    {
        this.setState({ date: new Date() });
    }

    render() 
    {
        return (
            <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
            </div>
        );
    }
}

Props


this.props

"props" are read-only, no matter how to define your component.

Consider "pure" functions, which do not change their inputs and always return the same output when given the same input.

All React components must be pure in respect to their "props".

State


this.state

Reserve this object for state information about your component.

You can only assign directly to "this.state" in the constructor.

Changing "this.state" directly will not cause the element to be re-rendered.
Use "this.SetState(object)" instead.

Reset the entire state of the component:

this.setState(object);
"setState" will merge the provided object into the current state, so you can update single variables at a time without losing the others.

Updates to "this.props" and "this.state" are managed by React asynchronously, and may be paused or batched.
If the "next" state values are calculated based on the "current" values, you must use this:

this.setState((state, props) => ({
    counter: state.counter + props.increment
}));

Decomposition

Components can refer to other components.

It is common to start an entire web application from one "App" component.


function Welcome(props) 
{
    return <h1>Hello, {props.name}</h1>;
}

function App() 
{
    return (
        <div>
          <Welcome name="Sara" />
          <Welcome name="Cahal" />
          <Welcome name="Edite" />
        </div>
    );
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
);

Design components the way you would an object oriented model. Each component should be reusable and do just its own job.

Design

No component should care if another component is stateful or stateless.

No component should care if another component is a function or class component.

A component can pass its state "down" as props to a child component.
Data is never passed "up" from child to parent component.
aka Top down data flow
aka Unidirectional data flow
Events

React events are named in camelCase instead of lowercase.

Comparison:

    //HTML passes a string
    <button onclick="activateLasers()">
        Activate Lasers
    </button>
    //JSX passes a function
    <button onClick={activateLasers}>
        Activate Lasers
    </button>

You can add all event listeners to elements when they initialized, instead of calling "addEventListener" after the element is created.

Default Behavior

In Javascript, you can return "false" from an event handler to cancel default behavior.

In React, you must call "event.preventDefault()" to do this.

function ActionLink() 
{
    function constructor(props)
    {
        super(props);

        // This binding is necessary to make "this" work in the callback
        this.handleClick = this.handleClick.bind(this);    
    }

    //your event handlers will usually be methods in the component class
    function handleClick(e) 
    {
        e.preventDefault();
        console.log('The link was clicked.');
    }

    return (
        <a href="#" onClick={this.handleClick}>
            Click me
        </a>
    );
}

Synthetic Event

React passes synthetic events to your event handlers. They are cross-browser compatible.

Arguments

To pass additional arguments to an event handler:

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    //OR
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
In both examples, the event handler will expect arguments (id, event).
Conditions

If

Example: only display the "You have X unread messages" text if there are unread messages.

return (
    <div>
        <h1>Hello!</h1>
        {unreadMessages.length > 0 &&
            <h2>
                You have {unreadMessages.length} unread messages.
            </h2>
        }
    </div>
);
If the condition is "true", the expression will be evaluated.
If the condition is "false", the expression will be skipped.
This is based on core Javascript syntax.

Ternary


return (
    <div>
    {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
    ) : (
        <LoginButton onClick={this.handleLoginClick} />
    )}
    </div>
);
Lists

Generate a list of React elements.

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number, index) =>
    <li key={number.toString()}>{number}</li>
);

ReactDOM.render(
    <ul>{listItems}</ul>,
    document.getElementById('root')
);

Or

return (
    <ul>
        {numbers.map((number, index) =>
            <li key={number.toString()}>{number}</li>
        )}
    </ul>
);

Key

The "key" attribute is added to help React identify DOM elements that have been edited.
Keys should be unique within their list (among their siblings).
Usually you'll use data ids as your keys.
Use the list index if nothing else is available. (Not recommended if elements will change order in the list.)

If you create a component for an element that had a key on it, the key should be moved to the component tag.

function ListItem(props) 
{
    //no key here
    return <li>{props.value}</li>;
}

function NumberList(props) 
{
    const numbers = props.numbers;
    const listItems = numbers.map((number) =>
        //key is here, but is not passed in "props" to the component
        <ListItem key={number.toString()} value={number} />
    );
    return (
        <ul>{listItems}</ul>
    );
}

Controlled Components

HTML elements "input", "textarea", and "select" usually maintain their own state.
But React expects all state to maintained internally.

Controlled components are these HTML elements where React controls the state.

For data validation and other advanced techniques:
[Formik]

Input

Input example:

class NameForm extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.state = {value: ''};

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) 
    {
        //occurs on every change to the input value
        this.setState({value: event.target.value});
        
        //if you wanted the text to always be upper case
        this.setState({value: event.target.value.toUpperCase()});        
    }

    handleSubmit(event) 
    {
        //pop up an alert instead of submitting the form
        alert('A name was submitted: ' + this.state.value);
        event.preventDefault();
    }

    render() 
    {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Name:
                    <input type="text" value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

Textarea

Textarea example:

class EssayForm extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.state = {
            //initial text in textarea
            value: 'Please write an essay about your favorite DOM element.'
        };

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) 
    {
        this.setState({value: event.target.value});
    }

    handleSubmit(event) 
    {
        alert('An essay was submitted: ' + this.state.value);
        event.preventDefault();
    }

    render() 
    {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Essay:
                    <textarea value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

Select

For "select" tags, React marks the selected value in the "value" attribute of the "select" tag instead of on the "option".

Select (drop down) example:

class FlavorForm extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.state = {value: 'coconut'};

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) 
    {
        this.setState({value: event.target.value});
    }

    handleSubmit(event) 
    {
        alert('Your favorite flavor is: ' + this.state.value);
        event.preventDefault();
    }

    render() 
    {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Pick your favorite flavor:
                    <select value={this.state.value} onChange={this.handleChange}>
                        <option value="grapefruit">Grapefruit</option>
                        <option value="lime">Lime</option>
                        <option value="coconut">Coconut</option>
                        <option value="mango">Mango</option>
                    </select>
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

Multi-select: pass an array to "value"

    <select multiple={true} value={['B', 'C']}>

Controlling Multiple Inputs


class Reservation extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.state = {
            isGoing: true,
            numberOfGuests: 2
        };

        this.handleInputChange = this.handleInputChange.bind(this);
    }

    handleInputChange(event) 
    {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        //set state based on the name of the element
        //this uses ES6 computed property name
        this.setState({
            [name]: value
        });
        
        //ES5 equivalent
        var partialState = {};
        partialState[name] = value;
        this.setState(partialState);
    }

    render() 
    {
        return (
            <form>
                <label>
                    Is going:
                    <input
                        name="isGoing"
                        type="checkbox"
                        checked={this.state.isGoing}
                        onChange={this.handleInputChange} />
                </label>
                <br />
                <label>
                    Number of guests:
                    <input
                        name="numberOfGuests"
                        type="number"
                        value={this.state.numberOfGuests}
                        onChange={this.handleInputChange} />
                </label>
            </form>
        );
    }
}

Uncontrolled Components

The form data is handled by the DOM as usual.

Example:

class NameForm extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.input = React.createRef();
    }

    handleSubmit(event) 
    {
        alert('A name was submitted: ' + this.input.current.value);
        event.preventDefault();
    }

    render() 
    {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Name:
                    <input type="text" defaultValue="Bob" ref={this.input} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

File

File inputs must be uncontrolled components because the value can only be set by the user, not a program.

Tag "<input type='file'>".

Example:

class FileInput extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.fileInput = React.createRef();
    }
    
    handleSubmit(event) 
    {
        event.preventDefault();
        alert(
            `Selected file - ${this.fileInput.current.files[0].name}`
        );
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Upload file:
                    <input type="file" ref={this.fileInput} />
                </label>
                <br />
                <button type="submit">Submit</button>
            </form>
        );
    }
}

ReactDOM.render(
    <FileInput />,
    document.getElementById('root')
);


Lifting State

When more than one component needs to use the same state, lift the state to the nearest shared ancestor.

Recommended so you have a single place each piece of data is stored, which will greatly help debugging and changing features.

Example:

const scaleNames = {
    c: 'Celsius',
    f: 'Fahrenheit'
};

function toCelsius(fahrenheit) 
{
    return (fahrenheit - 32) * 5 / 9;
}

function toFahrenheit(celsius) 
{
    return (celsius * 9 / 5) + 32;
}

function tryConvert(temperature, convert) 
{
    const input = parseFloat(temperature);
    if (Number.isNaN(input)) 
    {
        return '';
    }
    const output = convert(input);
    const rounded = Math.round(output * 1000) / 1000;
    return rounded.toString();
}

class Calculator extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
        this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
        this.state = {temperature: '', scale: 'c'};
    }

    handleCelsiusChange(temperature) 
    {
        this.setState({scale: 'c', temperature});
    }

    handleFahrenheitChange(temperature) 
    {
        this.setState({scale: 'f', temperature});
    }

    render() 
    {
        const scale = this.state.scale;
        const temperature = this.state.temperature;
        const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
        const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

        return (
            <div>
                <TemperatureInput
                    scale="c"
                    temperature={celsius}
                    onTemperatureChange={this.handleCelsiusChange} />
                <TemperatureInput
                    scale="f"
                    temperature={fahrenheit}
                    onTemperatureChange={this.handleFahrenheitChange} />
                <BoilingVerdict
                    celsius={parseFloat(celsius)} />
            </div>
        );
    }
}

class TemperatureInput extends React.Component 
{
    constructor(props) 
    {
        super(props);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(e) 
    {
        this.props.onTemperatureChange(e.target.value);
    }

    render() 
    {
        const temperature = this.props.temperature;
        const scale = this.props.scale;
        return (
            <fieldset>
                <legend>Enter temperature in {scaleNames[scale]}:</legend>
                <input value={temperature}
                    onChange={this.handleChange} />
            </fieldset>
        );
    }
}
Composition

It is recommended to use composition over inheritance to reuse code between components.

Containment

For container-type components (don't know exactly what their children will be) it is recommended to use the special "children" prop. Other components can easily pass children to the container with nested JSX.


//container
function FancyBorder(props) 
{
    return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
            {props.children}
        </div>
    );
}

//another component passes "h1" and "p" into "props.children"
function WelcomeDialog() 
{
    return (
        <FancyBorder color="blue">
            <h1 className="Dialog-title">
                Welcome
            </h1>
            <p className="Dialog-message">
                Thank you for visiting our spacecraft!
            </p>
        </FancyBorder>
    );
}

If you need to specify more than one collection of children, you'll need to roll your own solution.


function SplitPane(props) 
{
    return (
        <div className="SplitPane">
            <div className="SplitPane-left">
                {props.left}
            </div>
            <div className="SplitPane-right">
                {props.right}
            </div>
        </div>
    );
}

function App() 
{
    return (
        <SplitPane
            left={<Contacts />}
            right={<Chat />} 
        />
    );
}

Specialization

Say you have a "Dialog" and a more specific "WelcomeDialog".
In object oriented programming, object "WelcomeDialog" would inherit from object "Dialog".
In React, "WelcomeDialog" will render "Dialog", with whatever specific settings it needs.

So it's actually like methods in any paradigm: the specific method calls on the general method.

You should not need any React components to inherit from each other.


function WelcomeDialog() 
{
    return (
        <Dialog
            title="Welcome"
            message="Thank you for visiting our spacecraft!" />
    );
}

function Dialog(props) 
{
    return (
        <FancyBorder color="blue">
            <h1 className="Dialog-title">
                {props.title}
            </h1>
            <p className="Dialog-message">
                {props.message}
            </p>
        </FancyBorder>
    );
}