Javascript

Developing An Isomorphic GraphQL App With React

July 21st, 2016 | By João Carvalho | 4 min read

Understand what is an Isomorphic GraphQL App and how you can make one with React.

Single-page applications or SPAs are in trend.

SPAs emphasize a thick JavaScript client with a thin back end. Node.js takes this further with JavaScript on the client and the server.

Given the popularity of JavaScript, polyglot programming was put aside. What if I told you that the same code that runs on the server, also runs on the client? Yes, welcome to isomorphic programming in JavaScript.

In this take, I will introduce a bar tab app using isomorphic principles. This idea takes “code reuse” to new heights. For the demo, we'll leverage React and GraphQL to illustrate this idea.

For the impatient, feel free to examine the sample code on GitHub.

What Is Isomorphic?

Imagine this, JavaScript that runs both on the client and on the server. Can you think of where this starts to break down?

I can think of the DOM API getting in the way for instance. Node.js also has an API not available on the client. One way to do this is to push the limits of modularity.

Start by extracting what is not tight-coupled and share those modules across boundaries. React has already done the heavy lifting with a virtual DOM. The example below illustrates the concept.

var react = typeof React === 'object' ? React : require('react');

var drink = react.createClass({
    render: function() {
        if (this.props.drink) {
            return react.createElement(
                'p',
                null,
                react.DOM.strong(null, 'Drink: '),
                react.DOM.span(null, this.props.drink));
        }

        return null;
    }
});

if (typeof module === 'object') {
    module.exports = drink;
}


This is full of isomorphic concepts. The first line, for example, checks for an object called React. If it does not exist we bring in the library through Node.

The module.exports at the bottom makes drink available in Node. The browser treats the drink as a global module once you declare it. The code that creates Reactʼs component gets encapsulated through react.createClass. Reactʼs API was built around isomorphic principles.

The virtual DOM in React gets called through React.CreateElement. We make use of prepackaged virtual elements through React.DOM.

The this.props.drink is a props mechanism that makes data available to the component.

Hello, renderToString()

The beauty behind isomorphic apps is the core rendering happens both on the client and the server. Once again React makes this practical with renderToString().

var react = require('react');
var reactDomServer = require('react-dom/server');
var tab = require('./tab');

function render(data) {
    const tabElement = react.createElement(tab, data);

    return reactDomServer.renderToString(tabElement);
}


This code only runs on the server. the tab is the other React component that uses drink.

The tab component like drink runs both on the client and server. The react-dom/server is the central package that does the rendering on the server.

A similar technique happens on the client as shown below. The data parameter is how one initiates rendering on this component.

ReactDOM.render(React.createElement(tab, {}),
  document.getElementById('bar-tab'));


This time, use ReactDOM to do any extra rendering on the client. React will take the server-side HTML wrapped around a div bar tab.

The HTML declares <div id="bar-tab">{{reactComponent}}</div>.

With component rendering happening on both client and server. Can you imagine what this means for the web? I remember a time when JavaScript was not a guarantee for the client.

Many search engine crawlers and accessibility tools still do not support JavaScript. JavaScriptʼs initial purpose was to make pages dynamic and enhance the experience.

Progressive Enhancement With GraphQL

Progressive enhancement is an ancient and battle-tested technique. React handles GraphQL queries on the server as shown below.

getInitialState: function() {
    return {
        query: this.props.query,
        drink: this.props.drink
    };
}


The props mechanism activates when you pass values into the data parameter. GraphQL queries the data in Node:

const queryString = url.parse(req.url, true).query;
const drinkQuery = queryString['bar-query'];

graphql.graphql(schema, drinkQuery).then(function(drink) {
    request.data = getViewData({
        query: query,
        drink: JSON.stringify(drink)
    });

    engine.render(request, res, renderEngine);
});

function getViewData(data) {
    return {
        reactComponent: react.render(data)
    };
}


The request object is a way to make the data available to the renderEngine. Note the reactComponent and react.render is what ends up on server-side rendering. Now I double-dog dare you to turn off JavaScript! What is so radical is the React component will behave much the same way.

On the client, a similar story occurs with JavaScript. This time instead of a full page reload, do partial updates. Ajax is a common technique for this as shown below.

handleSubmit: function(e) {
    e.preventDefault();

    const xhr = new XMLHttpRequest();
    xhr.open('GET', `/ajax?bar-query=${this.state.query}`, true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

    xhr.onload = function(eXhr) {
        const xhrResponse = eXhr.target;

        this.setState({
            drink: xhrResponse.responseText
        });
    }.bind(this);

    xhr.send();
}


There is a separate Ajax route that deals with Ajax calls from the client. The setState changes the state of components through JavaScript. React uses this as part of its state mechanism, so I bind(this) in the Ajax callback. Feel free to explore the rest of the Ajax route that happens on the server.

With progressive enhancement, I am free to take the initial HTML and add to it. The beauty here is I get this for free with React.

Conclusion

Isomorphic apps bring back the battle-tested techniques of the past.

What is most exciting is how this idea is a natural progression from SPAs. It shows what JavaScript can do when it runs both on the client and server. React and GraphQL explore only a glimpse of what is possible.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Web Development

Build Isomorphic Apps with Next.js

In this tutorial, we'll build a simple timer component in React that is isomorphic and leverages Next.js for universal rendering.

May 15, 2019 | By Camilo Reyes | 4 min read

Javascript Tutorials Web Development

Getting Started with GraphQL

GraphQL is a declarative, compositional, and strong-typed query language. Useful for querying dynamic data with a strong-typed schema.

May 11, 2016 | By Camilo Reyes | 4 min read

Section Divider