Understanding React Native Fundamentals

Ethan Holmes

February 2016

You might not be familiar with how React for Web works, so we are going to cover the fundamentals in this article. We will also explain the core principles of how React for Web works under the hood. Once you have a solid understanding of the basics, we will dive into how React for Web works and the subtle differences between mobile and web. By the end of this article, you will have the necessary skills to start building the example application.

(For more resources related to this topic, see here.)

In this article we will cover the following topics:

  • The Virtual DOM
  • Introducing components and JSX
  • Writing our first component
  • Props and state of components

The Virtual DOM

Do you know how to write a JavaScript function? If you do, that's great! You're well on your way to understand how React and React Native work under the hood. What do we mean exactly? Well, when you research how React works, you'll eventually encounter someone explaining it in the following manner:

UI = f(data)

You may say, Nerd alert! How is this helpful? Well, it's saying that your UI is a function of your data. To put it in more familiar terms, let's say that:

var todos = function(data) { return data.join( " -- " ) }

You can call the function with an array of data, such as:

var ui = todos( ["wake up", "get out of bed", "drag a comb across my head"] );
console.log(ui);

This is not a particularly earth-shattering code; however, you're now rendering some content, in this case to the console.

What if, all your UI rendering code could be this predictable? It can be! Let's start getting a little more advanced. What if, in addition to our todos() function, we had a function called todoItem(), such as:

var todoItem = function(data) { return "<strong>" + data + "</strong>" }

That looks a lot like our original UI function, doesn't it?:

UI = f(data)

What if we start composing our todos() and todoItems(), such as:

var ui = todos( [todoItem("wake up"), todoItem("get out of bed")] );

You can start to get the picture that we can start to render more and more complex outputs by composing simple functions.

What if we want to start rendering our content to the browser? I'm sure you can imagine changing our todoItem() to add elements to the DOM using jQuery; however, in this case we will start repeating ourselves a lot with many instances of appendChild() calls and jQuery selectors. If we are really smart, we might write a framework to abstract away the DOM manipulations so that we can write the code that matters to our application, not just the code that matters to the browser.

OK, so now let's say that we've magically got a framework that lets us represent our UI as a data function and we don't have to think about how our content will get rendered to the DOM. We can start changing our data over and over and watch the DOM update! That sounds great in theory, but when we have dozens of div elements in a deeply nested hierarchy, the underlying DOM manipulations become complex and inefficient.

What if our magic framework had an intermediate representation of the DOM? Let's call it Virtual DOM and let's say that instead of making every little change to the DOM, we batch the changes together. We can even compare the before and after states of the Virtual DOM. Figure out the differences and reduce the number of real DOM manipulations that we need to perform. Now we're really on to something!

So we can now express our UI as a function of our data. We don't have to think about the underlying DOM manipulation code and our UI is nice and snappy because the underlying framework is really smart and reduces the number of DOM manipulations it needs to perform. It will be pretty great to have a framework that could do that for us, but you know what will be really cool? What if the DOM didn't have to be a browser DOM? What if that same abstraction that allows us to write the code that matters to our app could be used to, say, update native mobile components? Enter React Native.

Components

Now here is an interesting problem; we have come across this great framework for making fast differences between the Virtual DOM and its native components. How do we tell React Native what UI to represent or when to change it? A React Native component is a simple, reusable, function-like object that enables us to describe the native mobile components we want to render. They will always contain properties, state, and a render method. Let's start really simple by creating our own component.

Creating your first component

Creating a new component in React Native will look similar to the following:

import React, {
Text,
View
} from 'react-native';
class HelloComponent extends React.Component {
render () {
   return (
   <View>
     <Text>Hello React</Text>
   <View>
);
}
}

Remember to import the React Native module. Here, we are using the ES6 import statement; it is similar to how the node require module works.

Wait a second… What are these weird XML elements doing in my JavaScript code? Facebook has created its own syntactic extension over JavaScript to describe React components. Here is the exact same code, but written in ordinary JavaScript:

var HelloComponent = React.createClass({displayName:   "HelloComponent"}, render: function () {
return (
   React.createElement(View, null,
     React.createElement(Text, null, "Hello React")
)
));

While it is possible to write React Native applications only in JavaScript, the previous syntax includes many added benefits for the developer.

JSX

JavaScript XML (JSX) is an XML-like extension to the ECMAScript specification. It combines the component logic (JavaScript) and markup (DOM or Native UI) into a single file.

A JSX Element will take the following form:

var element = (
<JSXElement>
   <SubJSXElement />
   <SubJSXElement />
   <SubJSXElement />
<JSXElement />
);

The JSX specification also defines the following:

  • The JSX Elements can be either self-opening <JSXElement></JSXElement> or self-closing <JSXElement />.
  • Accept attributes as an expression {} or string "" <Component attr="attribute">. Expressions are JavaScript snippets.
  • The children elements can be text, expressions, or elements.

What if you have more than one component or a list of components?

There can only be a single root element; it means that if you have multiple components, you must wrap them in a parent component.

This is cool! We have gone from a deeply nested and imperative JavaScript code to a declarative format that describes the exact elements that we want to see in our components. There is no separation of concerns since our logic is coupled with our markup, making the components easier to debug and test. Since you can always include the same component in multiple other components, there is no need to duplicate the code anyway.

Note that JSX is only meant to be used as a preprocessor and it is not recommended to transpile in your production build. More information on JSX can be found in the official React documentation https://facebook.github.io/react/docs/jsx-in-depth.html or in the official JSX Specification https://facebook.github.io/jsx/.

Back to our first component

There are a few things that we have overlooked in our component. View and Text are two of the many components provided by React Native to build a UI. These are not regular components that render in the JavaScript layer, they can map directly to their native container parts! The View component maps to UIView in IOS and android.view in Android, while Text is the generic component to display text on each platform respectively. View and Text support various functions, such as layouts, styling, and touch handling.

Displaying the same static text over and over is not very exciting. Let's extend this simple component and add some more functionalities.

Props and state

At this point, you may be wondering how React Native deals with component manipulation and communication as the number of components grows into a component hierarchy. A component hierarchy, similar to a tree, starts with a root component and can contain many children. React Native provides two methods of data passing; one for data-flow down the component hierarchy and another for maintaining internal state.

Props

How do the components in the same component hierarchy communicate with each other? Data is passed down through properties commonly known as props. Props are considered to be immutable by convention and should never be modified directly. To pass a prop into a component, just add a camel-cased attribute to the component:

<HelloComponent text="Hello React" />
Props can be accessed internally in the component through this.props:
import React, {
Text,
View
} from 'react-native';

class HelloComponent extends React.Component {
render () {
   return (
     <View>
       <Text>{this.props.text}</Text>
     View>
   );
}
}

What if I want to pass down a lot of props?

It is possible to pass an array of props to a component using the ES7 spread operator <HelloComponent {...props} />.

It is not always necessary to include props with a component, but if you require a default value for your props, you can assign the defaultProps object to the component's class constructor.

HelloComponent.defaultProps = {text: "Default Text!"};

Validating props

If you are planning to expose your component to the public, it makes sense to constrain the ways developers can use it. To enforce that your components are being used correctly, the PropTypes module can be used to validate any props passed in. In the event that a prop does not pass the propType validation, a warning is shown to the developer in the console. The PropTypes cover a wide range of JavaScript types and primitives, including nested objects. You can define propTypes on a component's class constructor:

HelloComponent.propTypes = {text: React.PropTypes.string};

For more information on propTypes, visit the Prop Validation section of React Docs https://facebook.github.io/react/docs/reusable-components.html.

State

So now we can pass in the data, but what if the data changes, then how can we display these changes to the user? Components can optionally contain state, a mutable and private set of data. State is a great way to keep track of user input, asynchronous requests, and events. Let's update our component with additional text when the user interacts with it:

import React, {
Text,
View,
Component
} from 'react-native';
class HelloComponent extends React.Component{
   constructor (props) {
     super(props);
     this.state = { // Set Initial State
     appendText: ''
   };
}
render () {
   return (
     <View>
       <Text onPress={() => setState({text: ' Native!'})}>{this.props.text + this.state.appendText}</Text>
        <View>
   );
}
}

Touching the Text component will trigger the function in its onPress prop. We are taking advantage of the ES6 arrow syntax to include our functionality in line with the text component.

Using the ES6 arrow syntax will automatically bind this to a function. For any non-arrow function, if you need access to this then you need to bind the value to the function in the props expression <Text onPress={this.myFunction.bind(this)}>.

The setState function will merge the object you pass into the first argument with the current state of the component. Calling setState will trigger a new render where, instead of being empty, this.state.appendText will append Native! to the value of text, which we originally passed in from props. The final result is "Hello React" + " Native!" to produce "Hello React Native!".

Never try and modify the value of this state on your own. Directly changing the state could result in data loss during the next setState call and it will not trigger another re-render.

Summary

Now hopefully, you understand the radical new direction React has taken in achieving performance. The Virtual DOM handles all of the DOM manipulations for us behind the scenes. At the same time, it uses efficient diffing algorithms to minimize the number of calls to the DOM. We have also seen how JSX allows us to express our components declaratively and combine our application logic into a single file. By using props and state, we can pass the data through components and update them dynamically.

I hope you can now take the information you learned in this article and convince your boss to start using React Native right away!

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Getting Started with React Native

Explore Title
comments powered by Disqus