Book Image

Mastering React Native

Book Image

Mastering React Native

Overview of this book

React Native has completely revolutionized mobile development by empowering JavaScript developers to build world-class mobile apps that run natively on mobile platforms. This book will show you how to apply JavaScript and other front-end skills to build cross-platform React Native applications for iOS and Android using a single codebase. This book will provide you with all the React Native building blocks necessary to become an expert. We’ll give you a brief explanation of the numerous native components and APIs that come bundled with React Native including Images, Views, ListViews, WebViews, and much more. You will learn to utilize form inputs in React Native. You’ll get an overview of Facebook’s Flux data architecture and then apply Redux to manage data with a remote API. You will also learn to animate different parts of your application, as well as routing using React Native’s navigation APIs. By the end of the book, you will be able to build cutting-edge applications using the React Native framework.
Table of Contents (20 chapters)
Mastering React Native
Credits
Disclaimer
About the Authors
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Props and PropTypes


The components that we've seen so far are completely static in that they take no external input and always render exactly the same. This isn't especially interesting because the same outcome can be achieved by writing plain old HTML. However, React provides a mechanism for making components dynamic by using properties, or props.

Accepting props

Props are passed into a component in order to modify their base definition. Let's take another look at our Title component:

import React, { Component } from 'react'; 
 
export default class Title extends Component { 
 
  render() { 
    return ( 
      <h1> 
        Hello World! 
      </h1> 
    ); 
  } 
 
} 

While the title of a single article might be Hello World!, this component needs to be more dynamic if it is to be reused within all of our NewsItem components. For this, we'll use a React input property, or prop, called titleText. React component methods have a this context that gives access to properties that have been passed in:

import React, { Component } from 'react'; 
 
export default class Title extends Component { 
 
  render() { 
    return ( 
      <h1> 
        {this.props.titleText} 
      </h1> 
    ); 
  } 
 
} 

Once again, remember that curly brackets in JSX denotes JavaScript code. Here, we are accessing the component's titleText prop in order to render it within the component's markup:

<h1> 
  {this.props.titleText} 
</h1> 

PropTypes

This by itself is sufficient code to start accepting a titleText property. However, as a best practice, we should include in our component's definition a description of what properties it is equipped to accept. While this may seem like over-engineering and unnecessary in small projects maintained by a single developer, as the project and team grows, explicit definition of properties is key in an untyped language such as JavaScript.

Defining PropTypes in a component is how we formally tell other developers what properties a component accepts and what value types those properties should be. PropTypes are the same across instances of a component and are thus statically attached to the class:

import React, { Component, PropTypes } from 'react'; 
 
export default class Title extends Component { 
 
  render() { 
    return ( 
      <h1> 
        {this.props.titleText} 
      </h1> 
    ); 
  } 
 
} 
 
Title.propTypes = { 
  titleText: PropTypes.string 
}; 

Adding PropTypes to a component does not change anything functionally, but it will cause annoying warning messages to be logged to the JavaScript console when they are disobeyed (only when React is in development mode, mind you).

To use PropTypes, we'll need to add it to the React import:

import React, { Component, PropTypes } from 'react'; 

The PropTypes module comes with functions for validating different value types, such as string, number, and func.

Here, what we are communicating is that this component takes one optional property called titleText, and that property should be of type string:

Title.propTypes = { 
  titleText: PropTypes.string 
}; 

We could also make this a required property:

Title.propTypes: { 
  titleText: PropTypes.string.isRequired 
} 

In addition to having string type props, we can also have other simple types, such as booleans and numbers:

Title.propTypes = { 
  titleText: PropTypes.string.isRequired, 
  highlighted: PropTypes.bool, 
  fontSize: PropTypes.number 
}; 

Props can not only be used to define the text content, but can also be used to define attributes of an element, for instance, inline style:

import React, { Component, PropTypes } from 'react'; 
 
export default class Title extends Component { 
 
  render() { 
    return ( 
      <h1 
        style={{ 
          backgroundColor: this.props.highlighted ? 'yellow' : 'white', fontSize: `${this.props.fontSize}px` 
        }} 
      > 
      {this.props.titleText} 
      </h1> 
 
    ); 
  } 
 
} 
 
Title.propTypes = { 
  titleText: PropTypes.string.isRequired, 
  highlighted: PropTypes.bool, fontSize: PropTypes.number 
}; 

One thing to note with the preceding example is that CSS properties that have a dash in them when written in traditional CSS use camel case in React inline style. This is because keys in JavaScript objects cannot contain dashes.

React PropType specifications can also be used to validate more complex properties. For instance, we could have a property that is either a string or a number using the oneOfType function, which is as follows:

fontSize: PropTypes.oneOfType([ 
  PropTypes.string, 
  PropTypes.number 
]) 

Likewise, we can specify a set of specific values that a property is allowed to take by using the oneOf method:

size: PropTypes.oneOf([ 
  'small', 
  'medium', 
  'large' 
]) 

We can of course specify more complex data types, such as arrays and objects, but we can also be more specific and describe the types of values in an array property or the shape that an object property takes:

propTypes: { 
  //Array that can contain anything 
  simpleArray: PropTypes.array, 
 
  //Object that can contain anything 
  simpleObject: PropTypes.object, 
 
  //Array that contains only Number values 
  arrayOfNumbers: PropTypes.arrayOf(PropTypes.number), 
 
  //Object that takes a specific "shape" 
  complexObject: PropTypes.shape({ 
    id: PropTypes.number, 
    name: PropTypes.string 
  }) 
} 

Now our Title component is getting interesting. It has gone from something that can be easily recreated using just HTML to something more like a HTML template-still declaratively defined, but dynamic in that it can take external properties.

Alternatively, PropTypes can be added to a React component as a static property using the static keyword:

import React, { Component, PropTypes } from 'react'; 
 
export default class Title extends Component { 
 
  static propTypes = { 
    titleText: PropTypes.string.isRequired, 
    highlighted: PropTypes.bool, 
    fontSize: PropTypes.number
} 
 
  render() { 
    return ( 
      <h1 
        style={{ 
          backgroundColor: this.props.highlighted ? 'yellow' : 'white', fontSize: `${this.props.fontSize}px` 
        }} 
      > 
        {this.props.titleText} 
      </h1> 
 
    ); 
  } 
 
} 

This syntax is cleaner, but is not officially part of the ECMAScript specification at this point. While most transpiler programs will recognize this syntax, we'll avoid it in this book for that reason.

Passing props

With a component defined that accepts props, the next step is for props to be passed into this component. In the case of our Title component, the NewsItem component can pass properties into the contained Title component. It does this using the attribute syntax of XML:

import React, { Component } from 'react'; 
import Title from './Title'; 
 
export default class NewsItem extends Component { 
 
  render() { 
    return ( 
      <div className="news-item"> 
        <Image /> 
        <Title 
          titleText="Hello World!" 
          highlighted={true} 
          fontSize={18} 
        /> 
        <Byline /> 
        <Description /> 
      </div> 
    ); 
  } 
 
} 

Strings are the only value types that can be passed in as a prop directly:

titleText="Hello World!" 

For other JavaScript data types, such as numbers, Booleans, and arrays, we must surround the values in curly braces so that they are interpreted correctly as JavaScript:

fontSize={18} 

For Boolean props, we can shorten their input to where the property name's presence is interpreted as true and its absence is interpreted as false, much like in HTML:

<div className="news-item"> 
  <Image /> 
  <Title 
    titleText="Hello World!" 
    highlighted 
    fontSize={18} 
  /> 
  <Byline /> 
  <Description /> 
</div> 

Default props

In a previous section, we specified, using PropTypes, that the titleText property of the Title component is required, but the other two properties are optional. This raises an interesting question: what will the value of those properties be if they are not specified? Well, without any intervention from the component developer, those properties will appropriately have the value undefined when no value is passed in. This could be problematic in some situations.

For our fontSize property, a value of undefined could lead to some unpredictable and potentially error-prone code because it is expecting a number. Luckily for us, React has a mechanism for specifying default values for optional properties that have not been passed in explicitly. This mechanism is a method on the component called defaultProps and we can use it in Title, statically, like this:

import React, { Component, PropTypes } from 'react'; 
 
export default class Title extends Component { 
 
  render() { 
    return ( 
      <h1 
        style={{ 
          backgroundColor: this.props.highlighted ? 'yellow' : 'white', 
          fontSize: `${this.props.fontSize}px` 
        }} 
      > 
        {this.props.titleText} 
      </h1> 
 
    ); 
  } 
 
} 
 
Title.propTypes = { 
  titleText: PropTypes.string.isRequired, 
  highlighted: PropTypes.bool, 
  fontSize: PropTypes.number 
}; 
Title.defaultProps = { 
  highlighted: false, 
  fontSize: 18 
}; 

defaultProps must be a JavaScript object where keys are property names and the values are the default values to use in the case that no values were passed in for that particular property. We can now define a Title component that isn't highlighted and has the default font size of 18 pixels by simply writing the following:

<Title 
  titleText="Hello World!" 
/> 

In context, our NewsItem component is now simplified to this:

import React, { Component } from 'react'; 
import Title from './Title'; 
 
export default class NewsItem extends Component { 
 
  render() { 
    return ( 
      <div className="news-item"> 
        <Image /> 
        <Title 
          titleText="Hello World!" 
          highlighted 
        /> 
        <Byline /> 
        <Description /> 
      </div> 
    ); 
  } 
 
} 

Sometimes, a component will receive its props from several levels above. For instance, maybe NewsFeed specifies the title of an individual NewsItem, rather than having NewsItem provide it statically itself, as we have done in the previous examples. Parameterizing this property allows the NewsItem component to be more generic and reusable:

import React, { Component, PropTypes } from 'react'; 
import Title from './Title'; 
 
export default class NewsItem extends Component { 
 
  render() { 
    return ( 
      <div className="news-item"> 
        <Image /> 
        <Title 
          titleText={this.props.titleText} 
          highlighted 
        /> 
        <Byline /> 
        <Description /> 
      </div> 
    ); 
  } 
 
} 
 
NewsItem.propTypes = { 
  titleText: PropTypes.string.isRequired 
}; 

Here, we have shown how the NewsItem component can accept a property, and in turn, pass it down to the Title component.

Props.children

Every component has an optional special property that is called children. Normal properties, as we have seen, are passed in using something similar to the HTML attribute syntax:

<Title 
  titleText="Hello World" 
/> 

You can also pass in text or other component elements by placing them in between an opening and closing tag. We can refactor our Title component to accept children instead of the titleText prop:

<Title> 
  Hello World 
</Title> 

Now, the render() method of our Title component becomes this:

render() { 
  return ( 
    <h1 
      style={{ 
        backgroundColor: this.props.highlighted ? 'yellow' : 'white', fontSize: `${this.props.fontSize}px` 
      }} 
    > 
      {this.props.children} 
    </h1> 
  ); 
} 

Note that we could now also pass in other React elements into the Title as property by also placing them in between the opening and closing tags:

<Title> 
  Hello World! 
  <img src="icon.png" /> 
</Title> 

When validating the children prop, we can use a special PropTypes called node, which means anything that can be rendered by React:

Title.propTypes = { 
  children: PropTypes.node.isRequired, 
  highlighted: PropTypes.bool, 
  fontSize: PropTypes.number 
};