< Previous Article Next Article >

React.js Apps

React is a popular client-side library made by Facebook designed for building user interfaces.

React forces you to think of your application in terms of components that manage their own state. Each component implements a render() method that takes input and returns what to display in JSX format.

Input data that is passed into the component can be accessed by render() via this.props.

class HelloMessage extends React.Component {
  render() {
    return (
      <div>
        Hello {this.props.name}!
      </div>
    );
  }
}

ReactDOM.render(
  <HelloMessage name="Alex" />,
  document.getElementById('root')
);

What is JSX?

In the example above, the render() method returns output as a JSX expression. JSX is a special type of syntax that adds XML or HTML directly into JavaScript. JSX is not valid raw JavaScript code, and therefore must be preprocessed by a tool called Babel.

Just like HTML or XML, JSX tags have attibutes; however, if an attribute is enclosed in braces ({}) instead of quotes, it is evaluated as a JavaScript expression. For example:

<MyCounter count={2 + 3} />;

Component State

In addition to taking input data (accessed via this.props), a component can maintain internal state data (accessed via this.state). When a component's state changes, the rendered markup will be updated by re-invoking render(). You can update a component's state by calling its setState() method.

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { seconds: 0 };
  }

  tick() {
    this.setState(state => ({
      seconds: state.seconds + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>
        Seconds: {this.state.seconds}
      </div>
    );
  }
}

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

Component Lifecycle Events

During the lifetime of a component, there is a series of events that get called. You can provide custom functionality for each event. In the example above, we used the componentDidMount() event, which gets called when the component is first rendered, and the componentWillUmount() event, which is called when a component is destroyed.

Interacting with the Server and the Database

Unlike a stateful application, where the flow is controlled by server-side code, React controls the flow of the application exclusively from client-side code.

In order to access the database, you must call out to the server via an AJAX request, which is a background request initiated by the browser to the server.

There are several techniques for initiating an AJAX request. Some of these techniques may require additional libraries like jQuery. However, in most recent browsers, a promise-based API called fetch() is now available, which allows you to make AJAX requests without any special library.

// Client-side React Component to list Product Lines
class ProductLines extends React.Component {
  constructor() {
    super();
    this.state = {
      list: [],
      message: null
    }
  }

  componentDidMount() {
    this.setState({ message: "Loading Product Lines..." });
    fetch("getProductLines")
    .then(response => response.json())
    .then(data => {
      this.setState({ list: data, message: null });
    })
    .catch(error => {
      this.setState({ message: error });
    })
  }

  render() {
    return (
      <div>
        <h2>Product Lines</h2>
        {
          this.state.message 
          ?
          <p className="message">{this.state.message}</p>
          :
          <ul className="product-lines">
            { this.state.list.map(item => (
              <li>
                {item.productLine}
              </li>
              ))
            }
          </ul>
        }
      </div>
    )
  }
}
// Server-side code to access the database
function getProductLines(request, response) {
  var productLines = pjs.query("SELECT productLine FROM productlines");
  response.send(productLines);
}
exports.default = getProductLines;

For a complete example, visit https://noderun.com/alex/react-product-selection/ or launch it here: https://noderun.com/run/alex/react-product-selection/.

React's Virtual DOM

The DOM (Document Object Model) represents a rendered HTML document in a browser.

However, manipulating the DOM can be slow, which is why the JSX code in React is first built into a Virtual DOM, a light-weight representation of the real DOM rendered in the browser.

This allows you to update a component's state without worrying about performance implications. React will, in turn, update only those parts of the browser content that have truly changed vs. re-rendering the entire page or component.

Using React with Rich Displays

Rich Displays greatly simplify React development because you can create your components visually in a point-and-click manner.

With Rich Displays, you can create a component using widgets in the Visual Designer, and then use the <RichDisplay /> component tag to reference it. A Rich Display component can be as simple as one or two widgets, or as complex as an entire screen.

Here is a simple Customer Grid being created in the Rich Display Visual Designer:

Screenshot

Once the design is saved, we can write a wrapper component called <Customers /> that fetches data into the grid.

// Customers Component rendered via <RichDisplay />
class Customers extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      customerGrid: []
    }
  }

  componentDidMount() {
    fetch("getCustomers")
    .then(response => response.json())
    .then(data => {
      this.setState({ customerGrid: data });
    })
  }

  render() {
    return <RichDisplay path="public/app.json" screen="customers" data={this.state} />
  }
}

<Customers /> embeds <RichDisplay /> and passes the necessary props: path, screen, and data.

Now, let's add a Customer panel in the Visual Designer.

Screenshot

We'll then add the <CustomerPanel /> wrapper component to load data into the panel.

// CustomerPanel Component rendered via <RichDisplay />
class CustomerPanel extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    app.getCustomer = this.getCustomer.bind(this);
  }

  getCustomer(custNum) {
    fetch("getCustomer?custNum=" + custNum)
    .then(response => response.json())
    .then(data => {
      this.setState(data);
    })
  }

  render() {
    return <RichDisplay path="public/app.json" screen="customerPanel" data={this.state} />
  }
}

We now have a full customer inquiry application.

Screenshot

If we ever need to add columns to the grid or additional database fields to the panel, we can do this easily in the Visual Designer without having to touch a line of code.

For the complete example, visit https://noderun.com/alex/using-visual-designer-with-react/, or try the app by visiting https://noderun.com/run/alex/using-visual-designer-with-react/.

Using React on NodeRun

An easy way to get started with React on NodeRun is to select one of the React templates presented when you're creating a new space.

Screenshot

You can also fork other React spaces you find on the NodeRun community site.

The templates and spaces provide the basic configuration for a React application, which includes a starting HTML file that loads the React library and Babel. By default, NodeRun spaces use the in-browser version of Babel during development. However, when you're ready to deploy a production application, it is advised that you precompile your React code using the Babel CLI (Command Line Interface).

Learning React

This document outlines React at a very high level. If you're brand new to React and JSX, you will likely want to find other resources to practice and gain a much deeper understanding of what React is capable of. You can start by referencing the offical React.js site (https://reactjs.org) and then proceed to find other online tutorials.

You can use NodeRun.com and its IDE as your playground for learning and experimenting with React in a full-stack environment. The Visual Designer available in the NodeRun IDE can help you build practical React components faster.

Questions?

Have questions about this topic? Ask for help on our NodeRun Discussion Forum.

< Previous Article Next Article >