Building web pages with React

Les Pinter

Introduction | What is React? | Installation | Components | Handling Events | Handling Data | Resources | Conclusion

Introduction

Once you've learned the fundamental skills of web page design (HTML, CSS and JavaScript), you'll probably start to think about automating some of your web page design work. Programmers can also use software tools; it's not just for clients any more.

Well, you're in luck, because several people have gone ahead of you and built tools to help you build and manage web pages more efficiently. The three most-mentioned JavaScript UI toolboxes are these:

I'm always tempted to call all three of them frameworks, but purists will remind me that only Angular is actually a framework. Angular has a speed advantage (and other advantages), but it comes at a substantial price. But unlike Angular, React and Vue can be added to web pages in your existing website without rewriting the entire site. This means that you can just dip your toes in the pool, rather than diving in head first.

I've purposely listed these three in order of their complexity. Vue is newest,easiest to learn and use, and least well-documented; React currently leads the field, and is a little harder to learn; and Angular is what Google uses to run their site, and is dizzyingly difficult to master. React has jumped to the fore as the toolbox of choice. It's also what Facebook uses for internal development.

Here's a graph that someone recently produced showing the relative percentages of developers using each product:

Fig. 01 - Relative popularity of JS frameworks

React is an excellent way to standardize your user interface. Once you master it, your work will be easier and more consistent.

What is React?

React is how FaceBook builds web pages. React is a combination of new tags and attributes and some JavaScript code to process them, and components that call a render() function that uses a technology called JSX (JavaScript Extended). (If you've looked at Microsoft's Razor Engine, where HTML and script are intermingled, that's analogous to JSX.) During the build, JSX is converted (using the Babel preprocessor) to the kind of JavaScript and HTML that modern browsers can understand.)

Here's a JSX example:

Listing 1: a React component

class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Apples</li>
          <li>Bananas</li>
          <li>Cherries</li>
        </ul>
      </div>
    );
  }
}

To use this component, just enter it as a tag, assigning a value to the name attribute, which is passed as a prop (property) in the component:

<ShoppingList name="Mark" />

So how do new tags and attributes work? As you may recall, there are about 100 tags - p, img, h2, etc. - in HTML 5. Each one has attributes - width, id, and so forth. React adds its own tags and attributes, which are processed by its considerable JavaScript function library.

Here's a little example of how custom tags and attributes work. Build a little HTML page that looks like this:

Listing 2: Tags and attributes

<!DOCTYPE html>
<html lang="en">
<head>
  <script>
    function colorMyTags() {
      var pTags = document.getElementsByTagName('Pinter');
      for (i = 0; i < pTags.length; i++)
      { var oneTag = pTags[i];
        oneTag.style.fontWeight = 'Bold';
        if (oneTag.hasAttribute('Shout'))
        { oneTag.style.color = 'Red';
          oneTag.style.fontSize = '24pt';
        }
      }
    }
  </script>
</head>
<body onload="colorMyTags()">
  <Pinter Shout>Good morning!</Pinter>
</body>
</html>

What's a Pinter tag? What's a Shout attribute? I made them up. My little script tells what to do with them:

Add about a few hundred tags, attributes and functions like that, with JavaScript to make use of them, and you've got your framework. Or, just use React.

Installation

You can "quick start" your React career by including three links in a web page:

However, that wouldn't give you all of the benefits of using React. The React methodology enforces several "best practices":

Note: JSX looks like HTML, but isn't. You can use the ".jsx" extension on files that contain JSX code, but you don't have to; Babel will know what to do with it if it finds JSX inside a .js file. You just write JSX in plain ole' JavaScript files, and the Babel compiler converts it into JavaScript when it finds it. So, of late the .jsx extension is being replaced by plain old ".js."

You must have node.js installed. To install it, go to nodejs.org and download and install the latest LTS (Long Term Support) version. I just got version 6.11.4, but by the time you read this, the version number may be higher. After it finishes installing, you'll see a Node Command Prompt window in the Start menu. Open it (you'll be in C:\users\<you>) and use create-react-app to create a new app folder and add all of the files needed for your new app. (Make sure the app folder name is lower-case; React requires it.)

npm install -g create-react-app
create-react-app react-test1
cd react-test1
npm start --open    &&rem (open in a browser at localhost:3000)

This will open the file C:\users\<you>\react-test1\src\index.html in your default browser:

Fig. 02 - src/Index.html

By the way, make sure you're sitting down, then open Windows Explorer and look at the properties for "C:\users\<you>\react-test1. It will contain, I kid you not, 22,662 files in 3,407 folders! Whiskey-Tango-Foxtrot?

Relax. When you build your website, a folder called build will be produced that contains about ten files, and that's all you need to deploy. Lots of stuff going on under the hood.

As the on-screen message says, you'll need to edit react-test1/src/index.js to make changes to your app. What you've built is a Single Page App (SPA), so all changes to the page involve loading content into elements (principally divs with ids). Your JavaScript (and JSX) code will generate content, which will be loaded into named elements in index.html without reloading the page. That's where a lot of the speed comes from.

Note that this is a Single Page App. I spent several days trying to figure out how to load another page, until it finally got through my thick skull that React apps don't load other pages. That's the whole point!

But I'm getting ahead of myself. Let's see how components work.

Components

There are several ways to write components. Let's take a look at them. (Note that in order to add a little visual pizazz, I added a class called first in app.css:

.first
{ text-shadow: 3px 3px 3px #333;
  color: red;
  font-size: 24pt;
  font-weight: lighter;
  font-family: 'Century Schoolbook';
}

Using classes that "extend" Component

First, rewrite app.js to look like this (note that you have to import Component in order to extend it):

Listing 3: app.js

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return React.createElement(
      'div',
      {className: 'App'},
      React.createElement(
        'h1',
        {className: 'first'},
        'Hello from App.js using createElement' ));
    }
}
export default App;

This approach uses the createElement() method in the React library. This is just JavaScript, which your browser will understand.

You can also write the following JSX:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
      <h1 className="first">Hello from App.js using JSX!</h1>
      </div>
    );
  }
}
export default App;

Looks a little simpler, doesn't it? The Babel compiler rewrites the JSX into the JavaScript shown above that uses React.createElement. That's why you use JSX.

Here's the app.css file:

Listing 4: app.css

body {
  margin: 0;
  padding: 0;
  font-family: 'Times New Roman';
}

h1  {
  color: red;
  font-size: 36pt;
  text-shadow: 3px 3px 3px #333;
}

Functions as components

You can define a component either as a function or as a class. We'll start with an example that uses a function. If you define a JavaScript function that returns JSX, you can pass it parameters and format HTML using their values. Add a folder called Person below src. Then, in the Person folder, add a JavaScript file called Person.js, and a text file called Person.css:

Listing 5: Person.js

import React from 'react';
import './Person.css';

const person = (props) => {
  return (
    <div className='Person'>
      <p>{props.name} Phone: {props.phone}</p>
      <p>{props.children}</p>
    </div>
  )
};

export default person;

-----------------------------------

Person.css:

.Person
{
  margin: auto;
  margin-top: 10px;
  width: auto;
  min-width: 350px;
  display: inline-block;
  padding-left: 15px;
  padding-right: 15px;
  margin-left: 10px;
  background-color: darkgreen;
  box-shadow: 3px 3px 3px #333;
  border: solid 1px black;
  color: white;
}

.p {
  color: 'Yellow'; 
  text-shadow: '3px 3px 3px #000';
}

input:focus { background-color: red; color: white; }

Change app.js to look like this:

Listing 6: app.js

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
render() {
    return (
    <div className="App">
        <h1>Hello from App.js using JSX!</h1><br />
        <Person name='Les' phone='(650) 464-6924' >
        I love to sing and play the guitar.
        </Person>
        <Person name='Wanda' phone='(713) 213-8892' >
        I love huntin' and fishin'.
        </Person>
    </div>);
  }
}

export default App;

localhost:3000 should now give you this:

Fig. 03 - Using a component in app.js

(If you closed your browser at some point, open the Node.js command prompt, navigate to the folder where you installed your react app, and type npm start --open).

Now you see what props.children was for; it's a reserved word that displays any content that was included between the pair of component tags.

Note that we can nest components. app.js is a component; so is Person. Nesting can be (and often is) quite deep.

State

When you create components as classes, you get an additional capability called state that you don't have access to when you define your components as functions. State is a collection of data values that persist from one component to another. Props are set outside of components and passed into them; state is set inside components and shared among them.

That doesn't mean that you should always use classes to create components. On the contrary, functions are simpler, cleaner, and probably a few other things that end in "-er." But if you want to pass values around your app, state is how you do it, and for that, you'll need to subclass the Component class. (That's what "extends" does - it subclasses the Component class.)

Change app.js as follows:

Listing 7: app.js

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
state = {
  persons: [
    { name: 'Les', phone: '(650) 464-6924' },
    { name: 'Wanda', phone: '(713) 213-8892' }
  ]
}

render() {
    return (
    <div className="App">
        <h1>Hello from App.js using JSX!</h1><br />
        <Person 
         name={this.state.person[0].name} 
         phone={this.state.person[0].phone} >
        I love to sing and play the guitar.
        </Person>
        <Person
         name={this.state.person[1].name} 
         phone={this.state.person[1].phone} >
        I love huntin' and fishin'.
        </Person>
    </div>);
  }
}

export default App;

Go back to your browser, and - tada! - no change. So far, so good.

But there is a change. When data is stored in state variables, it can be bound to objects that extract those values from state and display them. Later in this class, you'll learn how to return data from a server (a SQL Server, to be precise) and store it in state variables. That's where the rubber hits the road.

Debugging JavaScript in Chrome

Before we go further, you need to know how to debug JavaScript. First, use Google's Chrome browser. It's got the best debugging features, and it's free. All of the others are free as well, but free isn't always a bargain.

Click on the three little vertical buttons at the upper right of the Chrome screen; select More Tools, then Developer Tools:

Fig. 04 - Selecting the debugger from inside Chrome

The debugger window appears. Press F5 (or re-enter localhost:3000 as the URL):

Fig. 05 - The debugging window

If an error occurs, the code step-through stops on the line that threw the error and displays the error message! Before JavaScript, I had never worked with a language that didn't tell you why your code had bombed. Whose idea was that? (Probably the same idiot that made JavaScript case-sensitive...)

If you put the word debugger; anywhere inside your JavaScript code, when you launch your page, the code will stop on the debugger; line and wait for you to click on one of the little icons below the code listing to continue running your JavaScript code. You can display the values of program variables as well. So now you know what to do when it becomes apparent that you didn't type in the code from this article correctly. :)

By the way, see that little link to Download the React DevTools? Click on it. It just takes a second, and you're trying to learn React, so why not?

Handling Events

Events are handled in the browser. There are thirty or so events, but a mouse click is one of the more commonly handled events. So let's add a button with a named event handler method, and write some event handler code.

First, in app.js, add an event handler named clickHandler just before the call to render():

clickHandler = () => { console.log('Clicked!'); }

render() { ...

Next, add a button just before your Person objects:

<button onClick={this.clickHandler}>Click me<button>

Note that the capital 'C' in onClick is mandatory; this ain't JavaScript. (The name clickHandler is completely arbitrary. Ending the name with "-Handler", however, is a naming convention that helps you distinguish between event-handlers and other types of JavaScript functions.)

Open Chrome and the Debugger, and then load your page using localhost:3000. When you click on the button, the word Clicked! appears as the last line in the debugger output panel.

Passing an event handler reference (a property) to a component

But what if you want the Click event to be associated with the component itself, without adding a button? It just takes two steps:

  1. Add a Click property to the Person class in the container, and
  2. Associate that property with the onClick handler assignment in the component.
Listing 8: app.js with an event handler defined

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
    state = {
        persons: [
            { name: 'Les', phone: '(650) 464-6924'},
            { name: 'Wanda', phone: '(713) 213-8892'}
        ]
    }

    clickHandler = () => { console.log('Clicked!'); }

    render() {
    return (
    <div className="App">
        <h1>Hello from App.js using JSX!</h1><br />
        <button onClick={this.clickHandler}>Click me!</button><br />
        <Person
         name={this.state.persons[0].name}
         Click={this.clickHandler}
         phone={this.state.persons[0].phone} >
         I love to sing and play the guitar.
         </Person>
        <Person
         name={this.state.persons[1].name}
         Click={this.clickHandler}
         phone={this.state.persons[1].phone} >
         I love huntin' and fishin'.
         </Person>
    </div>);
  }
}

export default App;

The component needs to define the reference using the same property name, by pointing to the Click property in the container's properties:

import React from 'react';

const person = (props) => {
  return (
    <div className='Person' title='Click me!' onClick={props.Click}>
      <p>{props.name} Phone: {props.phone}</p>
      <p>{props.children}</p>
    </div>
  )
};

export default person;

(Note that if Click had a capital C in the component, the reference to it in the container also has to have a capital C.)

Clicking on the component increments the console log display of the string Clicked!.

Fig. 06 - Clicking on the Person component calls the event handler that was defined in the container

This is actually pretty profound, because it allows const components that don't have access to the state to call methods in classes that do have access to the state. Passing a reference as a property from a class to a function is a common way to share functionality. More on that later.

Passing a parameter

With a small change in the code, we can pass a parameter using an event handler. This time we'll change some of the data displayed on the screen. Add a new event handler called switchNameHandler with a new collection of persons. (Note the use of the bind method to attach the event handler to the first card, and the function syntax in the second card. Both do the same thing.)

Listing 9: Preparing an event handler to receive a parameter (app.js)

switchNameHandler = (newName) => {import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
  state = {
    persons: [
      { name: 'Les', phone: '(650) 464-6924'},
      { name: 'Wanda', phone: '(713) 213-8892'}
    ]
  }

  switchNameHandler = (newName) => {
    this.setState({
      persons: [
        { name: newName, phone: '(650) 464-6924'},
        { name: 'Wanda', phone: '(713) 213-8892'}
      ]
    })
  }

  render() {
    return (
      <div className="App">
        <h1>Hello from App.js using JSX!</h1><br />
        <button onClick={this.switchNameHandler.bind(this,'Les')}>
        Reset me!
        </button><br />
        <Person
          name={this.state.persons[0].name}
          Click={this.switchNameHandler.bind(this,'Jolene')}
          phone={this.state.persons[0].phone} >
          I love to sing and play the guitar.
        </Person>
        <Person
          name={this.state.persons[1].name}
          Click={()=>this.switchNameHandler('Anna')}
          phone={this.state.persons[1].phone} >
          I love huntin' and fishin'.
        </Person>
      </div>);
    }
}

export default App;

The setState method defines a new collection of persons, with a parameter to pass a value into the method which will replace the name of the first person object. When you click on the first card, the name changes to Jolene. Click the second card, and the name changes to Anna (You can add a tooltip telling your users where to click by adding 'title='Click me!' to the component.

Fig. 07 - The name on the first card changes to 'Jolene'

Note that in large applications, bind is faster.

Adding a button to show/hide names

Can we add logic to toggle the display of names on/off? Yes, but perhaps not the way you thought. We can't really add an if  block here. But we can use a ternary expression that evaluates to either true or false, and we display a block of JSX if it's true, and doesn't if it's not:

if (true/false expression) ? [do if true] : [do if false]

Change app.js to look like this:

Listing 10: Using a ternary expression to toggle elements on/off (app.js)

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
    state = {
      persons: [
        { name: 'Les', phone: '(650) 464-6924'},
        { name: 'Wanda', phone: '(713) 213-8892'}
      ],
      showPersons: false
    }

    switchNameHandler = (newName) => {
      this.setState({
        persons: [
          { name: newName, phone: '(650) 464-6924'},
          { name: 'Wanda', phone: '(713) 213-8892'}
        ]
      })
    }

    togglePersonsHandler = () => {
      const doesShow = this.state.showPersons;
      this.setState({showPersons: !doesShow});
    }

    render() {
    return (
    <div className="App">
        <h1>Hello from app.js!</h1><br />
        <button onClick={this.togglePersonsHandler}>
         Toggle names
         {this.state.showPersons ?
          <span>Off</span> :
          <span>On</span>}
          </button><br />
        {
          this.state.showPersons ?
            <div>
              <Person
              name={this.state.persons[0].name}
              Click={this.switchNameHandler.bind(this,'Jolene')}
              phone={this.state.persons[0].phone} >
              I love to sing and play the guitar.
              </Person>
              <Person
              name={this.state.persons[1].name}
              phone={this.state.persons[1].phone} >
              I love huntin' and fishin'.
              </Person>
            </div>
          : null
         }
    </div>);
  }
}

export default App;

Here's the result:

Fig. 08 - Showing names
Fig. 09 - Hiding names

I'm assuming that by now you can see how it's done by looking at the code. However, I made a few typographical errors while building this example, and catching and correcting the mistakes in those few blue lines of code took me about ten minutes. JavaScript and JSX and both very, very picky.

While the two Persons are visible, open the debugger and select Elements, and you'll see this:

Fig. 10 - The div is visible

Toggle the names off, and the div disappears.

Fig. 11 - The div is gone!

This shows yet another way in which React differs from classic HTML/JS: In the past, we would create a <div> containing something, and mark it visibility: hidden. But the HTML would still be there, and would still be served every time that the .html file was loaded. With React, the HTML is in a JavaScript file; it isn't even loaded until the program requests it.

You can also define a new state variable that's either (1) null or (2) contains the entire rendered div, and move the JSX to the top of the render() method:

Listing 11: A more elegant approach to conditional HTML generation (app.js)

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
  state = {
    persons: [
      { name: 'Les', phone: '(650) 464-6924'},
      { name: 'Wanda', phone: '(713) 213-8892'}
    ],
    showPersons: false
  }

  togglePersonsHandler = () => {
    const doesShow = this.state.showPersons;
    this.setState({showPersons: !doesShow});
  }

  render() {

    let persons = null;
    if(this.state.showPersons) {
      persons = (
        <div>
        <Person
        name={this.state.persons[0].name}
        phone={this.state.persons[0].phone} >
        I love to sing and play the guitar.
        </Person>
        <Person
        name={this.state.persons[1].name}
        phone={this.state.persons[1].phone} >
        I love huntin' and fishin'.
        </Person>
        </div>
      );
    }

    return (
    <div className="App">
      <h1>Hello from app.js!</h1><br />
      <button onClick={this.togglePersonsHandler}>
      Toggle names
      {this.state.showPersons ?
        <span>Off</span> :
        <span>On</span>}
        </button><br />
        { persons }
    </div>
    );

  }

}

export default App;

This is perhaps a more elegant way to deal with conditional HTML content.

You can do something analogous to this with styling. You add some styles to app.css, then conditionally construct an array of style names based on various conditions (e.g. 'red', 'bold'), and then use varName.join(' ') to build a string of classnames from your array of classnames, as required by the classNames attribute.

However, you can also use an add-on called 'Radium' that gives you all of that and much more. To use it,

NOTE: There is another way to do styling: CSS Modules. They give you a way to only apply styles to a specific component. However, CSS modules are an advanced topic, so until you need them, avoid them.

You can then do all sorts of styling, including assigning pseudo-class selectors (like ":hover") by class name, in your code. Radium will post-process it and make it all work. See especially the use of <StyleRoot> and media queries, which are made infinitely easier by using Radium. Looks a little funny at first, but follow the examples. Formidable.com/open-source/Radium has lots of them.

Building a collection of objects

But (of course) there's better way to deal with lists of objects. We can use the JavaScript map method to create a collection of objects, which is easier to manipulate in code. This method iterates over the persons collection that you put into state using JSON (JavaScript Object Notation), and maps its elements into a collection of objects of type <Person>:

Listing 12: Using map to create an array of objects (app.js)

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person';

class App extends Component {
  state = {
    persons: [
      { name: 'Les', phone: '(650) 464-6924'},
      { name: 'Wanda', phone: '(713) 213-8892'}
    ],
    showPersons: false
  }

  togglePersonsHandler = () => {
    const doesShow = this.state.showPersons;
    this.setState({showPersons: !doesShow});
  }

  render() {

    let persons = null;
    if(this.state.showPersons) {
      persons = (
        <div>
        { this.state.persons.map( person => { return <Person
                    name={person.name}
                    phone={person.phone} />
              })}
        </div>
        );
    }

    return (
    <div className="App">
      <h1>Hello from app.js!</h1><br />
      <button onClick={this.togglePersonsHandler}>
      Toggle names {this.state.showPersons ?
        <span>Off</span> :
        <span>On</span>}
        </button><br />
        { persons }
    </div>
    );

  }

}

export default App;

This returns an array of JSX objects, which React will render as JavaScript, which will generate plain ole' HTML. That's usually how it's done.

Deleting an object

Often you need to add and delete objects in a colllection. To delete an object, add a deleteHandler, and write three lines of code for it. Look carefully at the deletePersonHandler code in Listing 13, below. The render() method adds a click property in each Person object that refers back to itself when you delete by clicking on a person. The click property contains a reference to index, the ordinal number of each object.

Note that in order to "delete" an element, the function simply copies every element except the one you want to delete. (You might want to insert a debugger; line at the top of the function and walk through it to see exactly what it's doing.)

By the way, in the setState call in the last line of the deletePersonHandler function, the first "person" refers to the state variable, and the second "person" refers to the local variable of the same name. JavaScript programmers think that this sort of confusing naming is just fine, so get used to it.

A commented line in listing 13 introduces the new ES6 spread (...) operator, which iterates over a collection or array. It's an easy way to copy collections, which you often have to do because array2 = array1 just assigns a pointer to array2, which, no matter what you do to array2, continues to be a just pointer to array1, rather than a copy of its contents.

Listing 13: Adding a delete handler (app.js)

  import React, { Component } from 'react';
  import './App.css';
  import Person from './Person/Person'

  class App extends Component {
    state = {
      persons: [
        { name: 'Les', phone: '(650) 464-6924'},
        { name: 'Wanda', phone: '(713) 213-8892'}
      ],
      showPersons: false
    }

    togglePersonsHandler = () => {
      const doesShow = this.state.showPersons;
      this.setState({showPersons: !doesShow});
    }

    deletePersonHandler = (personIndex) => {
      const persons = this.state.persons.slice();
      // Note that you can also use this:
      // const persons = [...this.state.persons];
      // "..." is the new ES6 spread operator. Google it.
      persons.splice(personIndex,1);
      this.setState({persons: persons});
    }

    render() {

      let persons = null;
      if(this.state.showPersons) {
        persons = (
          <div>
          { this.state.persons.map( ( person, index ) => {
            return <Person
                    click={() => this.deletePersonHandler(index)}
                    name={person.name}
                    phone={person.phone} />
              })}
          </div>
          );
      }

      return (
      <div className="App">
        <h1>Hello from app.js!</h1><br />
        <button onClick={this.togglePersonsHandler}>
        Toggle names {this.state.showPersons ?
          <span>Off</span> :
          <span>On</span>}
          </button><br />
          { persons }
      </div>
      );

    }

  }

  export default App;

I did something cute at the end of render(): I used another ternary expression to add either 'On' or 'Off' at the end of the string "Toggle names " depending on the boolean value of this.state.showPersons. Work your way through the logic; it will be worth the effort.

By passing the index (the item number of each member of the collection) of the <Person> object in its call to deleteHandler, we give the handler what it needs in order to remove the correct element (actually, to copy all elements except the deleted one.)

You now have to give Person.js a way to receive notification that the Person card was clicked. All you have to do is pass the new click property via props. A ToolTip to tell them that they can "Click to delete" is a nice touch, unless your users are mind readers.

Listing 14: Passing the new click property to Person.js:

import React from 'react';
import './Person.css';

const person = (props) => {
  return (
    <div className='Person' onClick={props.click} title='Click to delete'>
    <p>{props.name}     Phone: {props.phone}</p>
    <p>{props.children}</p>
    <input type="text" onChange={props.changed} value={props.name}/>
    </div>
  )
};

export default person;

Adding keys and using them to target a single object in a list

In order to uniquely identify a particular object, you should include a primary key with a unique value for each object. In SQL Server, you can use the IDENTITY(1,1) specification to automaticaly generate consecutive integer values starting with 1 to be used as the primary key:

Listing 15: Generating a primary key in a SQL Server table

CREATE TABLE CUSTOMER
( CustID Int IDENTITY(1,1) PRIMARY KEY,
  CustName VarChar(100) NOT NULL DEFAULT '',
  Active Bit NOT NULL DEFAULT 1
)

In React, you need to identify the key property. I'll just create my own key values for this example. As each object is being rendered, we include a call to the appropriate event handler - one for deleting an object, and one to apply a new name as it's typed (for which purpose I've added an <input> element in Person.js.) The click event to delete the object passes its index - its position within the list. The changed event passes the object's ID value. (Note that ID is all caps, unlike the id parameter). In the delete event handler, the deleteHandler copies all but the element to be deleted. In the changed event handler, the findIndex method is used to isolate the correct member, which then receives the keystrokes typed into the input box.

The changes needed in app.js are highlighted below:

Listing 16: Adding a key and using it to edit a list member:

import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person'

class App extends Component {
  state = {
    persons: [
      { ID: '1', name: 'Les', phone: '(650) 464-6924'},
      { ID: '2', name: 'Wanda', phone: '(713) 213-8892'}
    ],
    showPersons: false
  }

  togglePersonsHandler = () => {
    const doesShow = this.state.showPersons;
    this.setState({showPersons: !doesShow});
  }

  deletePersonHandler = (personIndex) => {
    const persons = this.state.persons.slice();
    // Note that you can also use this:
    // const persons = [...this.state.persons];
    persons.splice(personIndex,1);
    this.setState({persons: persons});
  }

  nameChangedHandler = ( event, id ) => {
    const personIndex = this.state.persons.findIndex( p => { return p.ID == id; } );
    const person = {...this.state.persons[personIndex]};
    person.name = event.target.value;
    const persons = [...this.state.persons];
    persons[personIndex] = person;
    this.setState({persons: persons})
  }

  render() {
    const style = {
      padding: '10px',
      backgroundColor: 'blue',
      color: 'white'
    }
    let persons = null;
    if(this.state.showPersons) {
      style.backgroundColor = 'orange';
      persons = (
        <div>
          { this.state.persons.map( ( person, index ) => {
            return <Personv
                    click={() => this.deletePersonHandler(index)}
                    name={person.name}
                    phone={person.phone}
                    key={person.ID}
                    changed={(event) => this.nameChangedHandler(event, person.ID)} />
              })}
        </div>
        );
    }

    return (
    <div className="App">
      <h1>Hello from app.js!</h1><br />
      <button onClick={this.togglePersonsHandler}> style={style};
        Toggle names {this.state.showPersons ?
        <span>Off</span> :
        <span>On</span>}
      </button><br />
      {  persons }
    </div>
    );

  }

}

export default App;

In nameChangeHandler, we locate the Person object uniquely identified by its ID value, replace the name with the string typed by the user, make a copy of state.persons, insert the changed Person back into the copy of the persons state variable, and use setState to overwrite state.persons with our copy of state.persons.

In case you're puzzled by the setState(person,person) statement, so is everyone else. The first argument in setState is always a state property. The second one is a local variable which just happens to have the exact same name as the state variable. I'd make it more confusing, if I could think of a way to do so...

I snuck in an example of conditional styling, using the property named style for the Toggle Names button. Initially it's white on blue, but if the names are to be displayed, it's white on orange. And just to confuse you, I used the name style to contain the style to which the button's style is set.

Finally, Person.js needs to point to the new changed property referenced in app.js:

Person.js with an input field that handles changes:

import React from 'react';
import './Person.css';

const person = (props) => {
  return (
    <div className='Person' onClick={props.click} title='Click to delete'>
    <p>{props.name}     Phone: {props.phone}</p>
    <p>{props.children}</p>
    <input type="text" onChange={props.changed} value={props.name} />
    </div>
  )
};

export default person;
Fig. 12 - The change event handler in action

As you type, the changed name is updated. Pretty cool, ┬┐no?

Debugging in Chrome

If your code encounters an error, it may or may not tell you exactly where it happened. But if you open Chrome Developer Tools, select Sources, open the module containing the error and click beside a line of code in the event handler, and then click on the event that triggers the handler, code execution will stop on your breakpoint. You can then hover over a property or object to see its value.

You can also install and use React Developer Tools, available from the Chrome Web Store. Restart Chrome, then choose React. When you open it, you'll see elements defined in your React app. It gives you insights that go beyond what the Chrome Developer Tools can give you.

If you want to see what your app will look like on an iPhone or iPad, click on the Toggle Device Toolbar icon to the left of the Chrome Debugger menu ( ). A dropdown just above your web page will give you several media screen size choices, so that you can see your page as it will appear on a phone or tablet. Use this in conjunction with @media tags to make your app responsive.


NOTE: THIS IS A WORK IN PROGRESS

Handling data

There are many resources to help you learn and practice coding with React and related technologies:

Conclusion

As of August 25th, there were 32,600 React jobs listed on Monster.com. Master this skill and triple your income.