Categories


Archives


Recent Posts


Categories


React: Hello Web Programmer

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

React is not the easiest development technology to learn.

A big part of the problem is the Hello World example and subsequent guide don’t do a lot to help along folks with a traditional web programming background. The Hello World tutorial can’t run without a giant in-browser IDE, and the successive guides go a little too-deep/too-fast on topics.

Regardless — React is hard to ignore, and most developers working in React don’t need to think too much about it. Their lead developer tells them how to manage props/state and which files to edit, and/or they learn a few boiler-plate copy/pastes and they’re good to go.

I wanted to understand things at more of a fundamental level. After doing my usual research this is the getting started tutorial I would have preferred. This tutorial assumes you have a working copy of Node.js installed and are familiar with basic package management using npm.

A Simple Development Enviornment

Our Build Tools

To start, we’ll need to use npm (which ships with Node.js) to create a project and then add three packages to that project as development dependencies.

$ mkdir react-hello-web-developer
$ cd react-hello-web-developer
$ npm init -y     # create a package.json file
$ npm install @babel/core --save-dev
$ npm install @babel/cli --save-dev
$ npm install @babel/preset-react --save-dev

All three of these packages are part of Babel. Babel is a javascript compiler, (and is sometimes called a transpiler). Babel can take a file written in one language, and compile it into another language. Or, in the more common case, Babel can take a file written in one dialect of javascript and transform it into another dialect of javascript.

The @babel/core package is the core babel project. Without it, the other parts won’t run. read more.

The @babel/cli package is a command line interface for babel. It will let us run npx babel to compile our React source files. read more

The @babel/preset-react package is a meta-package, and contains other Babel packages. These other packages contain the rules that allow babel to transform “React javascript” into something that will run in a standard javascript engine. read more

Our Source Files

We’ll want to create two source files. One will be the HTML shell that loads our compiled javascript, the other will be the React source file.

Create a new folder named public and create the following HTML file in that folder

<!-- File: public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
    <script src="main.js"></script>
</body>
</html>

This HTML file has a single div with an id of root

<div id="root"></div>

and then loads in React via the unpkg CDN.

<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="main.js"></script>

You don’t need to load these files from unpkg — you could host them locally if you want.

You also might have noticed we’re loading a file named main.js that we haven’t created yet.

<script src="main.js"></script>

Be patient, we’ll get to public/main.js momentarily.

Our React Source File

Before we can get to public/main.js, we need to create our React source file. Create a new folder named src and in that folder create a new file named src/main.js with the following contents.

// File: src/main.js
ReactDOM.render(
    <h1>Hello World</h1>,
    document.getElementById('root')
);

This is not the same file as public/main.js. In fact, it isn’t really javascript code either. This is a React source file, which is a special dialect of javascript that’s not compatible with standard javascript engines. If you tried running this in a browser or via Node.js, you’d end up with an error.

Uncaught SyntaxError: expected expression, got ‘<‘

There’s no quotes around <h1>Hello World</h1>. This is not a string, it’s something called a JSX component.

In order to run this stock React Hello World program, we’ll need to compile it into regular javascript.

Compiling our Program

To compile this program, we’ll use babel. Run the following program from the command line

$ npx babel --presets=@babel/preset-react src/main.js
ReactDOM.render( /*#__PURE__*/React.createElement("h1", null, "Hello World"), document.getElementById('root'));

The npx command (distributed with Node.js and npm) will run command line programs that your project’s packages have installed into ./node_modules/.bin/. i.e. the following two commands are equivalent

$ ./node_modules/.bin/babel --version
7.12.8 (@babel/core 7.12.9)

# npx is actually a little more complex than we desribed above
# but this isn't an npm tutorial.  The linked docs have more
# informaion on everything npx can do
# https://github.com/npm/npx#readme
#

$ npx babel --version
7.12.8 (@babel/core 7.12.9)

Babel’s --presets option tells babel to load the rules for compiling React javascript from the @babel/preset-react package we installed earlier.

The output

ReactDOM.render( /*#__PURE__*/React.createElement("h1", null, "Hello World"), document.getElementById('root'));

is our compiled program. Congratulations — you just compiled some React code into vanilla javascript!

Let’s compile this program and create a new src/main.js file in our public folder. You can do this by copy-pasting the generated code into pubilc/main.js, or by using a file the redirection operator.

$ npx babel --presets=@babel/preset-react src/main.js > public/main.js

Load public/index.html in a browser,

$ open public/index.html

and you’ll see your Hello World message bright as day.

Add Components

So that’s Hello World, but it doesn’t really tell us what makes React special.

React is all about rendering components. Components are javascript objects that render other components. When you pass a component to ReactDOM.render, you’re telling React that you want to render all your components, all its children, (and all it’s children’s children — all the way down) into browser DOM nodes. i.e. that you want to render them as part of the current HTML document.

Let’s rewrite our program to use a javascript component instead of that inline-jsx code we used earlier. Change src/main.js so it looks like the following

// File: src/main.js

class HelloWorld extends React.Component {
  render() {
    return <h1>Hello Component</h1>
  }
}

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

Recompile your program

$ npx babel --presets=@babel/preset-react src/main.js > public/main.js

and open your browser. You’ll see the new, Hello Component message.

What we’ve done above is define a new component by defining a new javascript class named HelloWorld that extends the base React.Component class.

// File: src/main.js

// React.Component is a base class provided by
// react.development.js -- in a "real" project
// you might need to import this class
//
// Components are usually, but not always, defined via classes.
// Non-class based components are called "funcional" components
    // and the open a whole can of worms as far as understanding what the 
    // heck is going on with react.  You can read more about them 
    // here: https://www.robinwieruch.de/react-function-component

class HelloWorld extends React.Component {
  render() {
    return <h1>Hello Component</h1>
  }
}

Then, we passed that component as the first argument to the ReactDOM.render method

// File: src/main.js

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

Notice that using this component means creating an HTML-like tag (<HelloWorld/>) from its class name. While React will ultimately render components as HTML nodes in the browser’s DOM tree, they are not, themselves, HTML.

Component Trees

Let’s consider a more complicated example. Replace your src/main.js file with the following

// File: src/main.js

class Address extends React.Component {
    render(){
        return <div>
            <AddressName/> <br/>
            <AddressStreet/> <br/>
            <AddressLocation/> <br/>
        </div>
    }
}

class AddressName extends React.Component {
    render() {
        return <strong>Pulse Storm LLC</strong>
    }
}

class AddressStreet extends React.Component {
    render() {
        return <span>PO BOX 9334</span>
    }
}

class AddressLocation extends React.Component {
    render() {
        return <span>
            <AddressCity></AddressCity>,
            <AddressRegion></AddressRegion>
            <AddressCode></AddressCode>
        </span>
    }
}

class AddressCity extends React.Component {
    render() {
        return <span>Portland</span>
    }
}

class AddressRegion extends React.Component {
    render() {
        return <span> OR </span>
    }
}

class AddressCode extends React.Component {
    render() {
        return <span>97207</span>
    }
}

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

Here we’re still rendering a single component

// File: src/main.js

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

However, this Address Component

// File: src/main.js

class Address extends React.Component {
    render(){
        return <div>
            <AddressName/> <br/>
            <AddressStreet/> <br/>
            <AddressLocation/> <br/>
        </div>
    }
}

renders an AddressName, AddressStreet, and AddressLocation component. Each of these components also renders further sub-components. Recompile your program, and you should see a mailing address rendered in your browser

This demonstrates how React lets you separate out various components of your interface. This both helps with development (everyone keeps their chocolate and peanut butter separate) and allows folks to create reusable components that can coexist on the same web page/application.

Automatically Updating UI

The other big selling point of React is how it manages a special variable called state. We’re not going to get too into the difference between props and state in React, but lets consider this final program

// File: src/main.js

/**
 * A global variable to hold a reference to our top component.
 *
 * Used for pedagogical purposes -- not something you'd
 * do in real life.
 */
let address

/**
 * This is an expedient base class created for
 * pedagogical purposes. You probably don't want
 * to do this.  The React core docs frown at
 * the existence of getDerivedStateFromProps (yet
 * is ships as part of the API?) and our use of it here
 * does mean javascript needs to allocate more objects
 * than it normally would if we did this "right"
 */
class DontDoThis extends React.Component {
    constructor(props) {
        super(props)
        this.state = Object.assign({}, props)
    }

    static getDerivedStateFromProps(props, state) {
        return Object.assign({}, props)
    }
}

class Address extends React.Component {
    constructor(props) {
        super(props)
        address = this
        this.state = {
            zip:97210,
            region:'OR',
            street:'PO Box 9334',
            name:'Pulse Storm LLC',
            city:'Portland'
        }
    }

    render(){
        return <div>
            <AddressName {...this.state}/> <br/>
            <AddressStreet {...this.state}/> <br/>
            <AddressLocation {...this.state}/> <br/>
        </div>
    }
}

class AddressName extends DontDoThis {
    render() {
        return <strong>{this.state.name}</strong>
    }
}

class AddressStreet extends DontDoThis {
    render() {
        return <span>{this.state.street}</span>
    }
}

class AddressLocation extends DontDoThis {
    render() {
        return <span>
            <AddressCity {...this.state}></AddressCity>,
            <AddressRegion {...this.state}></AddressRegion>
            <AddressCode {...this.state}></AddressCode>
        </span>
    }
}

class AddressCity extends DontDoThis {
    render() {
        return <span>{this.state.city}</span>
    }
}

class AddressRegion extends DontDoThis {
    constructor(props) {
        super(props)
        this.state = Object.assign({}, props)
    }
    render() {
        return <span> {this.state.region} </span>
    }
}

class AddressCode extends DontDoThis {
    constructor(props) {
        super(props)
        this.state = {
            zip:props.zip
        }
    }
    render() {
        return <span>{this.state.zip}</span>
    }
}

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

Replace your src/main.js with the above program, recompile, and load your program in the browser. You should see the address again

Next, open your browser’s javascript console,

and type the following

// `address` is our to level component obect
// exposed via a global variable
address.setState({
    name: 'Magento Inc.',
    region: 'CA',
    street: '3640 Holdrege Ave',
    city:'Los Angeles',
    zip:'90016'
})

Notice that immediately after calling this method, the entire component updated to a new address.

You didn’t need to write any new rendering code to update your component — you just told it about your new data, and React took care of re-rendering everything for you.

This is one of React’s super powers. It forces a separation between your data and your markup/design. Beyond being “the right” thing to do, this has a hidden (but intended) side benefit. By getting you out of the business of creating your own DOM elements React’s core code can optimize these often ill-performant operations. The direct creation of DOM nodes is one of a javascript’s biggest performance bottlenecks, particularly in a fully interactive web application delivered via the browser.

Wrap Up

There’s way more to React than this, of course. But at it’s core React is a system for writing HTML-like tags (called JSX). These tags corresponds to javascript objects that share data (called props and state) and have a mechanism for dynamically rendering/updating your UI/UX (usually the browser) whenever that state data is updated.

Series NavigationWhat is Magento PWA Studio >>

Copyright © Alan Storm 1975 – 2021 All Rights Reserved

Originally Posted: 14th December 2020