by

We briefly went through this topic in React Native Components tutorial. Let’s dive into more details on what state is, when to use it and when not, and build some apps using state!

What is State?

Components in React Native use state for data that changes over time. Most of your component should not use state, but take some data from props and render it. However, sometimes you need to respond to user input.

A common pattern is to create several stateless components that just render data, and have a stateful component above them in the hierarchy that passes its state to its children via props. The stateful component encapsulates all of the interaction logic, while the stateless components take care of rendering data in a declarative way.

Real Life Analogy

You can compare component’s state with a control panel in an airplane’s cockpit. There are many various switches, dials, and knobs on that panel for a pilot to interact with a plane. That’s a stageful component which encapsulates all of the interaction logic between a pilot and an plane.

Let’s say a pilot wants to deploy landing gear before landing. They pull the landing gear control knob on the panel, which changes landing-gear-deployed panel’s state from false to true, and the panel passes that changed state down to LandingGear component as a deployed prop. And all LandingGear does, it’s just constantly checking deployed prop and either deploys landing gear or pulls it back depending on true or false value. It doesn’t interact with a pilot directly.

You don’t want to design a plane control the way, that pilot would need to leave the cockpit and actually go to landing gear in order to deploy it. You want to keep all of the interactions with a user nice and tight within one single component above others in the hierarchy to make thing simple and minimize room for error.

What You Should Use State For

When component’s event handlers may change to trigger a UI update.

  • User input. For instance, a button that triggers a change in component’s UI or an input field.
  • Data that changes by timer. If you wanted to update component’s UI with timer, you would use state.

What You Should Not Use State For

Try to keep as many of your components as possible stateless. And you should never use state to store:

  • Computed data. Do all of your computation within render() method.
  • Components. Build them in render() method based on props and state.
  • Duplicated data from props. You should strive to have one source of truth for your data.

How State Works

You can get, store, and update data in state. When you update state, React Native automatically re-renders component using updated state. This way your UI is always up-to-date and you don’t have to worry about updating it manually.

Defining State

To define state just add state = { key: value } inside your component definition, where key is the name of a piece of data you want to store, and value is its value.

export default class App extends Component {

  state = {
    active: true
  }

}

Getting State

To get data stored in state use this.state.key.

export default class App extends Component {

  render() {
    <Text>{this.state.active}</Text>
  }

}

Changing State

To change state just call this.setState({ key: newValue }) in render() or other methods.

export default class App extends Component {

  render() {
    this.setState({ active: false });
  }

}

Example App

Let’s build a simple example app to illustrate how state works. We’re going to have a picture on the screen which changes depending on app’s state, and a button that changes state when tapped.

Create a New Project

Open Terminal App and run following commands to create a new app project and launch it in an emulator.

react-native init LearnignStyles;
cd LearnignStyles;
react-native run-ios;

Component Boilerplate

Open index.ios.js file and delete all of the code to start fresh. Let’s import components we’re going to need, define our component’s class, add state definition, empty render method, and empty styles outside of the class.

import React, { Component } from 'react';
import {
  AppRegistry,
  Image,
  StyleSheet,
  Text,
  TouchableHighlight,
  View
} from 'react-native';

export default class LearningState extends Component {

  state = {
    
  }

  render() {

  }
}

const styles = StyleSheet.create({

});

AppRegistry.registerComponent('LearningState', () => LearningState);

Next, let’s start filling our component boilerplate up with the code.

State

We’re going to have just one boolean value in state called happy. Let’s set it to false by default, so our dog is not so happy yet.

  state = {
    happy: false
  }

Render()

Next, let’s render our image and button. We’re using this.state.happy ? true : false condition to decide which image and button text we should use depending on current state. And we’re using TouchableHighlight component with onPress handler to change state.

Notice, how there is no logic to update our UI, when state is changed, present. React Native re-renders component automatically when we use this.setState() to change state.

  render() {
    return (
      <View style={styles.container}>
        <Image
          // Change an image depending on state
          source={{ uri: this.state.happy
            ? 'https://i.imgur.com/LNKc5V3.jpg' // happy
            : 'https://i.imgur.com/74KCGU8.jpg' // not happy
          }}
          style={{ width: 300, height: 300 }}
        />
        <TouchableHighlight
          underlayColor="#4FAD54" // darker color when tapped
          style={styles.buttonWrapper}
          onPress={() => {
            // Change state value to the opposite of current one
            this.setState({ happy: !this.state.happy });
          }}
        >
          <Text style={styles.button}>{this.state.happy
            // Change a button text depending on state
            ? 'Take that bone away' // happy
            : 'Give her a bone'     // not happy
          }</Text>
        </TouchableHighlight>
      </View>
    );
  }

Styles

And lastly, let’s fill up our styles.

const styles = StyleSheet.create({
  container: {
    flex: 1,                      // take all of the screen space
    justifyContent: 'flex-end',   // arrange children at the bottom
    alignItems: 'center',         // center children horizontally
  },
  buttonWrapper: {
    backgroundColor: '#8BC051',   // green background
    borderRadius: 4,              // round corners
    margin: 60,                   // add margins outside button
    padding: 15,                  // add padding inside button
  },
  button: {
    color: '#FFFFFF',             // white color
    fontSize: 18,                 // bigger font
  },
});

Result

Ok, let’s see what happens once we tap that button.

this.state.happy === false
this.state.happy === true

Challenge

Here is a little challenge for you. See, if you can change a button’s color to red when a dog is happy and post a comment with your solution.

Recommended Reading

Spread the Word
  • P A

    Hi,
    Would you know how to change the for two separate button components instead of changing the text wtihin the touchable opacity component? So you have one button component when pressed shows another button component?
    Thanks heaps.

  • Doug Sheridan

    Here is my solution to the proposed challenge:

    1. Add new style

    buttonWrapperOff: {
    backgroundColor: ‘#cb0e40’,
    }

    2. Set the TouchableHighlight style attribute using a tuple

    style={!this.state.happy
    ? styles.buttonWrapper
    : [styles.buttonWrapper, styles.buttonWrapperOff]}