Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering React Native

You're reading from   Mastering React Native Learn Once, Write Anywhere

Arrow left icon
Product type Paperback
Published in Jan 2017
Publisher Packt
ISBN-13 9781785885785
Length 496 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Eric Masiello Eric Masiello
Author Profile Icon Eric Masiello
Eric Masiello
Jacob Friedmann Jacob Friedmann
Author Profile Icon Jacob Friedmann
Jacob Friedmann
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Building a Foundation in React FREE CHAPTER 2. Saying HelloWorld in React Native 3. Styling and Layout in React Native 4. Starting our Project with React Native Components 5. Flux and Redux 6. Integrating with the NYT API and Redux 7. Navigation and Advanced APIs 8. Animation and Gestures in React Native 9. Refactoring for Android 10. Using and Writing Native Modules 11. Preparing for Production 12. React Native Tools and Resources

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.

You have been reading a chapter from
Mastering React Native
Published in: Jan 2017
Publisher: Packt
ISBN-13: 9781785885785
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime