React (Native) Essentials

Author

Spencer Carli

Developer, cat dad, and devout pizza lover. Teaching at React Native School and building apps with Handlebar Labs.

Last Updated: October 2, 2019

This is an introduction and reference guide to React/React Native. This guide is not all encompassing. It exists as a simple & quick one page reference. This guide makes the assumption that you're familiar with the basics of JavaScript. If not, or you feel like you're "missing" something, please reference the JavaScript Essentials guide.

What's the Difference?

What's the different between React and React Native? Basically just how they render things. The business logic (the thing that makes your app unique) is going to be the same for any project React targets - be it the web, native mobile apps, VR, etc. The foundation is the same it's just the code we write to actually build the UI that's different.

React targets the web. That means you're going to write HTML to build your interface. React Native targets native mobile apps that means you're going to be writing code that invokes the native equivalent.

React

<div>
  <p>Hello, world!</p>
  <input type="text" placeholder="Type here!">
</div>

React Native

import { View, Text, TextInput } from 'react-native';

<View>
  <Text>Hello, world!</Text>
  <TextInput placeholder="Type here!">
</View>

These components don't work exactly the same but they're similar enough that if you know one you'll be able to use the other with ease (and some help from the docs).

Please note that all of my subsequent examples will be using React Native to demonstrate.

Components - The Building Block

At the core all React (Native) apps are components. These components allow us to build complex UIs in a more simple way by separating logic into other more focused components.

There are two ways to create a component in React - using a JavaScript class and by writing a pure JavaScript function. I'll have examples of each for every example in this reference.

For a class component you'll extend React.Component and the only thing you have to do is set up a render method and return something from it. In this case we're just returning null (which is a valid React component).

Class Component

import React from 'react';
import { View, Text } from 'react-native';

class App extends React.Component {
  render() {
    return null;
}

<App />

For a function component you would just use the function syntax you're used to. You're most likely to see function components defined using fat arrow notation, though it isn't required.

Function Component

import React from 'react';
import { View, Text } from 'react-native';

const App = () => null;

<App />;

Additional Information

JSX - How You Render Content to the Screen

JSX is how you actually render content to the screen. It's an extension of JS that crosses over with HTML. It allows us to write components using a syntax very similar to HTML/XML.

You'll only be using JSX for things that will be rendered on the user's screen. Everything else is normal JavaScript.

Class Component

import React from 'react';
import { View, Text } from 'react-native';

class App extends React.Component {
  render() {
    return (
      <View>
        <Text>Hello, world!</Text>
      </View>
    );
  }
}

<App />;

Function Component

import React from 'react';
import { View, Text } from 'react-native';

const App = () => {
  return (
    <View>
      <Text>Hello, world!</Text>
    </View>
  );
};

<App />;

Additional Information

Props - Making Content Dynamic

Props are properties that can be passed to a component to enable dynamic functionality. A prop is passed on the instance of a rendered component. When a prop changes the component will re-render with the new data. So for the following examples if I changed "React Native School" to "Spencer" it would change the output from "Hello, React Native School!" to "Hello, Spencer!"

Class Component

import React from 'react';
import { View, Text } from 'react-native';

class App extends React.Component {
  render() {
    return (
      <View>
        <Text>Hello, {this.props.name}!</Text>
      </View>
    );
  }
}

<App name="React Native School" />;

Function Component

import React from 'react';
import { View, Text } from 'react-native';

const App = props => {
  return (
    <View>
      <Text>Hello, {props.name}!</Text>
    </View>
  );
};

<App name="React Native School" />;

State - Tracking Changes

State is how you're going to track any internal dynamic data in a component. Just like with props, when state changes the component will update to reflect that changed state.

To update state in a class component you'll use setState. If you depend on the previous value of a piece of state when you update it (like the example below) you want to use a function passed to setState so you guarantee you have the right value. If the next state value doesn't depend on the previous value you can just pass an object to setState with the value like this this.setState({ waveCount: 5 }).

You can set the initial state inside of the constructor method on the component. This is the only time you'll set this.state directly - every other time you need to use this.setState.

Class Component

import React from 'react';
import { View, Text, Button } from 'react-native';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      waveCount: 0,
    };
  }

  wave = () => {
    this.setState(state => {
      return {
        waveCount: state.waveCount + 1,
      };
    });
  };

  render() {
    return (
      <View>
        <Text>Hello, {this.props.name}!</Text>
        <Text>You've waved {this.state.waveCount} times.</Text>
        <Button title="Wave" onPress={this.wave} />
      </View>
    );
  }
}

<App name="React Native School" />;

You may also see initial state defined directly on the component

class App extends React.Component {
  state = {
    waveCount: 0,
  };

  // ...
}

Additional Information

Historically, function components couldn't hold their own state - they were only functions of their props. However, with the introduction of hooks, this has changed. Hooks are getting popular but a lot of code still uses class components so it's important to understand both. Class components are still perfectly valid and preferred by some (like me!).

Below you'll find the same component as before written with hooks. You'll see I need to import the useState hook and use it in my component. useState will take an initial value as the first argument to the function and it will return an array. The item at the first position will be the value (equivalent to this.state.waveCount) and the second will be a function to update that value.

Just like with setState you should never update waveCount directly - only modify it by calling the setWaveCount function.

Function Component

import React, { useState } from 'react';
import { View, Text } from 'react-native';

const App = props => {
  const [waveCount, setWaveCount] = useState(0);

  return (
    <View>
      <Text>Hello, {props.name}!</Text>
      <Text>You've waved {waveCount} times.</Text>
      <Button title="Wave" onPress={() => setWaveCount(waveCount + 1)} />
    </View>
  );
};

<App name="React Native School" />;

Additional Information

The Component Lifecycle

Just like us, a component has a lifecycle. It's born, it changes, and it dies. Components also have other lifecycle methods but these are the 3 you need to know.

For a class component you access these three things by three different methods.

  • Born: componentDidMount. The component is rendered on the screen.
  • Change: componentDidUpdate. The props or state has changed. You can also access the previous values in this method.
  • About to Die: componentWillUnmount. Unlike the others, this is called before the component is actually gone. This is done because once the component is gone we can no longer do anything with it.

Class Component

import React from 'react';
import { View, Text, Button } from 'react-native';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      waveCount: 0,
      onlineCount: 0,
    };
  }

  componentDidMount() {
    UserTracker.subscribeToOnline(this.userTracker);
  }

  componentDidUpdate() {
    console.log(`There are now ${this.state.onlineCount} online.`);
  }

  componentWillUnmount() {
    UserTracker.unsubscribeToOnline(this.userTracker);
  }

  userTracker = onlineCount => {
    this.setState({
      onlineCount,
    });
  };

  wave = () => {
    this.setState(state => {
      return {
        waveCount: state.waveCount + 1,
      };
    });
  };

  render() {
    return (
      <View>
        <Text>Hello, {this.props.name}!</Text>
        <Text>You've waved {this.state.waveCount} times.</Text>
        <Button title="Wave" onPress={this.wave} />
      </View>
    );
  }
}

<App name="React Native School" />;

Just like with state, historically a function component didn't have a lifecycle. It was there, it updated, and it died without telling anyone. With hooks this is no longer the case.

You can access a similar functionality using the useEffect hook. This hook is very powerful and we're just scratching the surface with this example.

Unlike a class component, all three lifecycle events will be represented within a single function. useEffect will accept a function as the first argument.

Inside of that function passed to useEffect there's not really a difference between the component mounting and updating. To tell when a component is about to unmount you can "cleanup" by returning a function from the function you passed to useEffect. This function will be called when the component is about to unmount.

Function Component

import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';

const App = props => {
  const [waveCount, setWaveCount] = useState(0);
  const [onlineCount, setOnlineCount] = useState(0);

  useEffect(() => {
    const userTracker = newOnlineCount => {
      setOnlineCount(newOnlineCount);
    };

    console.log(`There are now ${onlineCount} online.`);

    UserTracker.subscribeToOnline(userTracker);
    return () => {
      UserTracker.unsubscribeToOnline(userTracker);
    };
  });

  return (
    <View>
      <Text>Hello, {props.name}!</Text>
      <Text>You've waved {waveCount} times.</Text>
      <Button title="Wave" onPress={() => setWaveCount(waveCount + 1)} />
    </View>
  );
};

<App name="React Native School" />;

And there's my essentials guide to React (Native)! I scoured a few of my real world codebases to see what I actually use time and time again in actual apps.

React Native School Logo

React Native School

Get total access hundreds of tutorials, a dozen classes, and access to a community full of React Native developers by becoming a member of React Native School.

Join the email list to be notified of all new lessons and classes!