ReactForDrupal.com will use the information you provide on this form to send you newsletters and marketing by email. You can change your mind at any time by clicking the unsubscribe link in the footer of any email you receive from us or by contacting us at info@reactfordrupal.com.
We use Drip as our newsletter platform. By clicking below, you acknowledge that the information you provide will be transferred to Drip for processing in accordance with their privacy policy and terms.
We'll never sell or give away your info. We hate spam too!
By Sia Karamalegos and Joe Shindelar
The JavaScript ecosystem notoriously churns out new frameworks and libraries seemingly on a weekly basis. Blink and you may miss the next big thing. Even with all this churn, React has won the front-end race for a few years now. Why is that? One of the primary reasons is developer happiness. According to the State of JavaScript, in 2016, 92% of developers who had used it before would use it again, and that number rose to 93% in 2017. Those are the highest percentages among all frameworks surveyed, including Angular 1 and 2, Vue, Backbone, Polymer, Ember, and others.
In this article, we will give you a taste of why developers are so happy with React. We’ll also talk about how some of the concepts are similar or different from the Drupal and PHP world. But first, what is React? React is a JavaScript library for building user interfaces. It is not a framework. If you’re familiar with the MVC framework, it’s really only the V, or view. In a typical Drupal site a React front-end would replace your theme layer.
You can implement React in multiple ways. One is as a stand-alone front-end application that uses API endpoints from your Drupal app, as a headless CMS. You can also embed it directly in your Drupal front end, and pick and choose parts of your application to convert -- much the same way you might use jQuery with Drupal right now. The REST API in Drupal 8 Core, the JSON API module, and the GraphQL module all have made implementing React on a decoupled Drupal backend easier.
Why React?
One of the biggest reasons to use React is that it makes building the front end immensely easier than Drupal theming. Secondly, it can provide more complex user experiences that are also more performant. Finally, with React you can use other non-Drupal services to extend the features of your application.
Now let’s dive into the details...
Most of us have probably worked with top-down designs provided by page and screen. We then took those designs and broke them down into their containers, grid systems, and elements to write our markup. This is how Drupal core and most web development currently works.
Atomic Design, a design-systems methodology outlined by Brad Frost, states that we should start with the basic building blocks, or atoms, of a page and work our way up to create designs:
How does all of this relate to React? React is a component-based system of building user interfaces (UI). Developers write reusable components, starting at the "atomic" level, and work their way up to collections of atoms, layouts, and screens. We refer to this as the component hierarchy. Each of these atoms can receive data and have their own state, creating a powerful set of UI building blocks. Components are similar to Drupal or Twig templates in that they can be reused with different sets of data through variables, and assembled into a tree of layouts and elements.
Pattern Lab and Emulsify have made atomic design easier in Drupal through the use of "living" style guides. React takes this one step further with more flexibility, ease of developing and modifying, and composition of applications from components. In the next section, you’ll see how developing components is easier with one representation of a view.
In React, we write one full representation of a view. In other words, we put both the structure (markup) and behavior (events, etc.) in one place. Often, we put the style there too, but this isn’t required. For example, we might have a button with a click event. In React, the markup and click event are both in the same JavaScript file:
const Button = <button onClick={console.log('clicked!')}>Click Me</button>
However, when we use plain JavaScript or JQuery to write the same exact button, we need to write the structure in an HTML file:
<!-- HTML file -->
<button id="my-button">Click Me</button>
Then we need a separate JavaScript file to define the click event, find the target node, and add an event listener:
// JavaScript file
function onClick() {
console.log('clicked!');
};
const button = document.getElementById('my-button');
button.addEventListener('click', onClick);
In React, our HTML files usually have a normal <head>
, and the body contains a root node for our React application to target. All the rest of the markup is written in JavaScript alongside its behavior.
Having the structure and behavior in one place makes makes it easier to reuse elements and components, making atomic design possible. Both markup and script (and sometimes style) relevant to a particular "atom" is managed in one place.
Contrast this with Drupal themes, where modifying look and feel or even behavior can become a scavenger hunt. When it's time to make changes to a theme you first need to understand the unique configuration of the site, the organization of the theme, and all the decisions that the person before you made.
Components and their behaviors are intimately dependant and should be encapsulated like so. --James Long on Removing User Interface Complexity or Why React is Awesome
Unlike Drupal, React has no concept of a theme or template override. No templates, layouts, or components come with React. You either write your own or import an library of components. Either way, you have complete control over the markup, behavior, and style with less management of multiple layers of templates.
So what was that funny syntax we used for the button? Most React developers use JSX, or JavaScript XML, to create components that look similar to HTML but with the power of JavaScript expressions. For example, this is a simple JSX element representing an <h1>
tag with inner text:
const title = <h1>Hello, JSX!</h1>
You’re not required to use JSX with React, but the library encourages it and nearly the entire community uses it. Why? Here is the same code as above, but written without JSX:
const title = React.createElement(
'h1',
{},
'Hello, React!'
)
As you can see, JSX is both easier to read and less verbose. This is especially true once you start writing element trees with children. On top of that, you can drop JavaScript expressions wherever you need them. This works like variables in Drupal or Twig templates, but is far more powerful because you can write any JavaScript you want. It is not limited to just one subset of the language’s capabilities like Twig.
For example, below we have a more complex React component that outputs an input group with label and conditional error and helper text. All the curly brackets in the return statement are areas where JavaScript expressions are inserted. Sometimes it only has data like name or type, but sometimes it has conditionals or operations like Array.join:
const Input = (props) => {
const { labelText, type, name, required, helperText, errors } = props
const label = labelText ? labelText : nameToLabel(name)
const hasErrors = !isEmpty(errors)
return (
<label className={hasErrors ? 'is-invalid' : ''}>
{label} {required && <span className="required">*</span>}<br />
<input type={type} name={name} />
{hasErrors &&
<span className="error-text">{errors.join(', ')}</span>
}
{helperText &&
<span className="helper-text">{helperText}</span>
}
</label>
)
}
React is blazing fast across two dimensions:
For size and load time, out of all the major frameworks, it ranks second only to Vue at 97.5K raw and 31.8K compressed. Not all front-end assets are created equally. A 170K image may load, decode, rasterize and paint all in less than 3.41 seconds. On the other hand, 170K of JavaScript on the same network and device would take 6.9 seconds to load, parse and compile, and execute. JavaScript is your most expensive asset so library size matters.
Name | Size (minified) | Size (gzipped) |
---|---|---|
Vue 2.4.2 | 58.8K | 20.9K |
React 16.2.0 + React DOM | 97.5K | 31.8K |
Angular 1.4.5 | 143K | 51K |
Ember 2.2.0 | 435K | 111K |
Angular 2 | 566K | 111K |
In terms of responsiveness, React uses a virtual DOM. The virtual DOM is an ideal representation of the UI in memory. React syncs the real DOM with the virtual DOM through a process called reconciliation. The reconciliation algorithm diffs the before and after states to only re-render the parts of the DOM that changed. This results in less wasted renders and thus higher, or faster, responsiveness. React also provides a lifecycle method where you can override the algorithm to state whether a component should update or not.
In React, data only flows one way: down the component hierarchy. To update data, we send events up the hierarchy to trigger changes to data, or state, which then flow back down to the components.
To provide a little more context, React components can have 2 forms of data: props and state. Props are properties received from ancestors in the component hierarchy, and cannot be changed, or mutated. State is local to a component, and can be changed by events. Child components can receive both the values of that state and events to update that state through props.
In this example, the <Form>
component holds the values of firstName
and lastName
in state. The onChange
and onSubmit
events are also defined in the <Form>
. The <Input>
component is defined elsewhere, and it accepts props of name
, value
, and onChange
. The onChange
event is triggered in the child <Input>
component, which triggers an update to the <Form>
state, which flows back down to the <Input>
so we see the updated input value.
class Form extends React.Component {
constructor() {
super()
// Set initial state
this.state = {
firstName: '',
lastName: ''
}
}
// As the user types in an input, update the value in state for the
// property with the same `name` as the input.
onChangeInput = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
onSubmit = (e) => {
// Prevent the default browser POST action
e.preventDefault()
console.log(`Submitted! firstName: ${this.state.firstName}, lastName: ${this.state.lastName}`);
}
render() {
return (
<form onSubmit={this.onSubmit}>
<Input
name='firstName'
value={this.state.firstName}
onChange={this.onChangeInput} />
<Input
name='lastName'
value={this.state.lastName}
onChange={this.onChangeInput} />
<Button>Submit</Button>
</form>
)
}
}
One-way data flow ensures that the state remains the single source of truth for a component tree. It also decouples data from the view so that updates can be batched or done asynchronously. The good news is React does this for you in an optimized way to minimize unnecessary re-renders. Our applications become less buggy and easier to maintain. Winning!
React is a multi-platform library. Core React is written for web. It works both on the client and on the server with Node.js, so that you can also use server-side rendering.
React Native allows you to use React to write mobile applications with JavaScript. With React Native, you write one set of code that can compile to both iOS and Android applications.
ReactXP and React Native Windows are also extensions of React maintained by Microsoft to build on Windows and Xbox on the Universal Windows Platform (UWP).
Not all parts of the code on these different platforms is shareable, but they all follow the core concepts of React that we’ve discussed thus far in this article. One thing you will see shared across different platforms are universal component libraries. Write one set of components, render anywhere.
As a Drupal developer, you may or may not know JavaScript, and if you know it, you may or may not know ES6. So what is this ES6 you keep hearing about and why is it important in React?
"ES" is short for ECMAScript. ECMAScript is the standard used for ongoing development. The most popular implementation of ECMAScript is JavaScript. The number after "ES" refers to the edition of ECMAScript. You probably learned ES5 originally, which was released in 2009. ES6, also know as ES2015, was released in 2015, and included several new features. Now, development is happening more rapidly, and we also have ES7 (ES2016) and ES8 (ES2017). It can be very confusing, but for the most part, we generally refer to ES6 and above as ES6+ or ES2015+. Just to clarify, it’s all JavaScript but with new features that have been added through the years.
Why is this important in React? The React community has embraced ES6+ with open arms. A few years ago, tutorials and documentation were written in ES5. Currently, almost all tutorials and documentation are written using ES6+ syntax. To get onboard with React, you’ll have to learn some of JavaScript’s new features. It’s kind of like how Drupal 8 uses the latest version of PHP.
The good news...
As a PHP developer, ES6 is likely to be much more approachable than ES5 and earlier. For example, the new class syntax is very similar to PHP’s. You don’t have to learn every new feature of ES6 and above. A handful of things will help you get by, and once you learn them, I have a feeling you will like them a lot. I didn’t fall in love with JavaScript until I learned ES6.
So while you’ll have to learn something new, you’ll also be able to take advantage of both ease of use and performance benefits.
Similar to Drupal, React is open source. However, it was written by Facebook originally, which also drives the future development path of React. On the plus side, we have a huge company funding developers that work full-time on upgrades and enhancements. Open source contributors are welcomed with open arms to submit both issues and pull requests. The React team also publicly shares the meeting notes for their weekly meeting discussing future development and priorities. You can read more about contributing here.
React is lightweight partially because it is not opinionated about other tools you might want to use with it. For example, it comes with state management, but many people choose to use a separate state management package such as Redux or MobX. For single-page applications (SPAs), you can build your own router or use packages such as React Router or Next.js to manage routing for you.
Unlike Drupal where popular modules and patterns are often incorporated into core, React does not incorporate or adopt popular libraries. They keep the scope narrow so that React itself remains nimble and easier to update. Development is focused on delivering better on the core, including a relentless pursuit of higher performance to improve user experience. This also means that it is more difficult to define "best practices" in React since is it more of an ecosystem rather than a monolith like Drupal that standardizes over time.
One complaint that new JavaScript developers often have is that the ecosystem seems so vast, new tools appear seemingly each day, and some members of the community have so many strong opinions.
Since React itself is just one small package, the ecosystem to get a full application up and running can be intimidating. From ES6, Babel, and Webpack to npm to state management, routing, and sync requests, it can be a lot to learn for newcomers.
The good news is that better tools exist now for bootstrapping new React applications that don’t require you to learn how to best manage Babel and Webpack for transpiling and bundling your applications. Tools like Create React App and Next.js have been a godsend for helping new and experienced developers alike focus on React and get coding faster. The trend is to keep improving these tools that help make developer’s lives easier so that they can ship code faster.
Whether you’re interested in learning React or just trying to learn more about what makes it special, I hope you enjoyed this article. Do you use React? What are some of your favorite features and concepts?
Stay tuned for most posts from us on using React with Drupal!
If you want to study this deeper, here are some links that will help you out: