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

State


Occasionally, a component will need to keep track of some internal state in addition to the external, read-only, properties that are passed into it. State is necessarily internal to the component and, generally, exclusively tied to some visual display option (for instance, is the component visually expanded or collapsed).

Much in the same way that a component instance can access external properties via this.props, a component instance can access its internal state using this.state. Using internal state, we could optionally show parts of NewsItem only when that item is in an expanded state:

render() { 
  let body = null; 
 
  if (this.state.expanded) { 
    body = ( 
      <div> 
        <Byline /> 
        <Description /> 
      </div> 
    ); 
  } 
 
  return ( 
    <div 
      className="news-item" 
      onClick={this.onClick} 
    > 
      <Image /> 
      <Title 
        highlighted 
      > 
        {this.props.titleText} 
      </Title> 
      {body} 
    </div> 
  ); 
} 

We can see now that the body variable will only be defined if the internal state is expanded. Another thing we can see here is that a <div> element has been added around the description and byline. The reason we do this is because JSX elements must have a single root node in order to return them or store them in a variable. Alternatively, we could have stored each element in its own variable:

render() { 
  let byline = null; 
  let description = null; 
 
  if (this.state.expanded) { 
    byline = <Byline />; 
    description = <Description />; 
  } 
 
  return ( 
    <div 
      className="news-item" 
      onClick={this.onClick} 
    > 
      <Image /> 
      <Title 
        highlighted 
      > 
        {this.props.titleText} 
      </Title> 
      {byline} 
      {description} 
    </div> 
  ); 
} 

While this code is completely valid, we can make it even better by splitting out conditional rendering into a separate method:

renderBody() { 
  if (this.state.expanded) { 
    return ( 
      <div> 
        <Byline /> 
        <Description /> 
      </div> 
    ); 
  } 
  return null; 
} 

Then, we can use this helper method within our main render() method in order to make things a bit clearer:

render() { 
  return ( 
      <div 
        className="news-item" 
        onClick={this.onClick} 
      > 
      <Image /> 
      <Title 
        highlighted 
      > 
      {this.props.titleText} 
      </Title> 
        {this.renderBody()} 
      </div> 
    ); 
  } 

We've now seen how to use internal state to render things conditionally, but we have not yet seen how that state is defined or how it is modified. In React, we can specify the initial values of internal state by assigning them in the constructor of the component. The component's initial state, much like its default properties, should be a JavaScript object:

constructor(props) { 
  super(props); 
 
  this.state = { 
    expanded: false 
  }; 
 
  this.onClick = this.onClick.bind(this); 
} 

This method describes the initial state of a component, but it does not provide us with any means to update that state. In order to update the state of a component, we can use a React component's setState method to assign, or reassign, any internal state value.

Typically, updating state happens as a response to some user input or user event. In the last section, we learned how to define methods that respond to these user events, such as clicks, and how to attach these event listeners to the appropriate React element. Let's modify our onClick event handler to change the expanded state of our component instead of simply alerting:

onClick() { 
  this.setState({ 
    expanded: !this.state.expanded 
  }); 
} 

When we use setState in this way, React will notice that the internal state has changed, and this will trigger a new rendering using the new internal state. For this reason, we should never manipulate the state of a component directly:

//Do not do this 
this.state.expanded = false; 

If we change the internal state directly, React's rendering engine will not become aware of it and the component we see on our page will differ from the one in JavaScript. The same goes for props; they are external and should only be changed as a result of new values being passed in through JSX:

//Also don't do this 
this.props.titleText = 'Hello World!'; 

Now that we've demonstrated how to use internal state to display something conditionally, how to initialize state by setting it in the constructor method, and how to modify internal state in response to some user event using setState, let's look at all of this in context in our NewsItem component:

import React, { Component, PropTypes } from 'react'; 
import Title from './Title'; 
 
export default class NewsItem extends Component { 
 
  constructor(props) { 
    super(props); 
 
    this.state = { 
      expanded: false 
    }; 
 
    this.onClick = this.onClick.bind(this); 
  } 
 
  onClick() { 
    this.setState({ 
      expanded: !this.state.expanded 
    }); 
  } 
 
  renderBody() { 
    if (this.state.expanded) { 
      return ( 
        <div> 
          <Byline /> 
          <Description /> 
        </div> 
      ); 
    } 
    return null; 
  } 
 
  render() { 
    return ( 
      <div 
        className="news-item" 
        onClick={this.onClick} 
      > 
        <Image /> 
        <Title 
          highlighted 
        > 
          {this.props.titleText} 
        </Title> 
        {this.renderBody()} 
      </div> 
    ); 
  } 
 
} 
 
NewsItem.propTypes = { 
  titleText: PropTypes.string.isRequired 
}; 

Now we have a component for our news item that starts out collapsed (not expanded) and not showing the description or byline, but when the user clicks on the news item, it expands to show the two previously hidden elements.