Expo is a collection of tools that make it easier to code React Native apps. In this tutorial, I'm going to show you how you can quickly create React Native apps using Expo.

With Expo, developers can create React Native apps without all the frustrations that come with installing and configuring software dependencies such as Android Studio, Xcode, or all the other tools which are needed to develop and run a React Native app.

In this tutorial, I'm going to show you how to create a simple memory game using Expo. Along the way you'll also learn the following:

How to use the tools provided by Expo. This includes the CLI, SDK, and the Expo client app.

How to create a React Native app using Expo.

What Is Expo?

Expo is a framework for quickly developing React Native apps. It's like Laravel or Symphony for PHP developers, or Ruby on Rails for Ruby developers. Expo provides a layer on top of the React Native APIs to make them easier to use and manage. It also provides tools that make it easier to bootstrap and test React Native apps. Lastly, it provides UI components and services that are commonly only available when you install a third-party React Native component. All of those are made available via the Expo SDK.

Limitations of Expo

Before you proceed further, it's important to be aware of some of the limitations of Expo:

Expo apps don't support background code execution. This means that you can't, for example, run code that listens for location changes when the app is closed. Expos apps are limited to the native APIs that the Expo SDK supports. This means that if your app has a very specific use-case such as communicating with a Bluetooth peripheral, the only option to implement such functionality is with plain React Native, or by writing native code using a library called ExpoKit. Expo locks you into their toolset. This means you cannot simply install and use most of the great tools available for React Native development such as command-line tools, scaffolders, and UI frameworks. But the good thing is that the Expo SDK is compatible with plain React Native apps, so you won't have any problem when you eject your app from Expo. Standalone binaries of Expo apps can only be built online. Expo provides a command-line tool called Exp. This allows developers to initiate the build process on Expo servers. Once it's done, a URL will be provided to download the .apk or .ipa file.

Even with these limitations, it's important to keep in mind that Expo is a fully functional framework with lots of support for commonly used Android or iOS APIs. This means that it has got you covered for most of the functionalities that apps commonly need. So there's often no need to look outside of Expo to implement the native functionality.

App Overview

The app that we're going to create is a memory game. You may be familiar with this type of game—the user has to find matching pairs by turning over cards two at a time. Here's what the default screen looks like:

And here's how it looks like once all the pairs have been opened:

Once they've solved the game, the user can tap on the reset button to reset the items to their initial state. This allows them to start the game all over again.

Installing Expo

Unlike with plain React Native where you have to install and configure Android Studio or Xcode and other dependencies, with Expo there are only a few steps to follow in order to start developing apps:

Download and Install Node.js. Expo depends on the Node.js platform for its command-line tools and dependency management. Install the Expo Client on your iOS or Android device. This is used to preview the app while you're developing it. Install the command line tool. This allows you to generate a new Expo project, initiate a build process, and more. Execute the following command to install it:

Generating a New Expo App

Once you've installed all the dependencies, you can now generate a new Expo app:

Once that's done, it will create a new folder called MemoryGame. Navigate inside it and start running the development server:

Alternatively, you can also use the Expo XDE. This allows you to create and run Expo apps through a GUI. You can download the installer from the Expo GitHub repo. Currently, it only supports Windows and Mac. So if you're on Ubuntu or Linux it's better to stick with the command line for now.

Once the development server is running, you should now be able to see something like this:

That's the QR code which points to the live preview of the project. Open the Expo client app on your phone and scan the code using the QR scanner. At this point, you should now be able to view the default screen. Every time you hit Control-S on any of the project files, the preview should automatically reload to reflect the changes.

You can find the full source code of the project on its GitHub repo. Or if you want to give the app a try, you can check out the demo. Just select QR Code, and scan it on your phone using the Expo client app.



Coding the App

Now we're ready to code the app. Let's begin with some UI components before we go back and implement the main component.

Header Component

The header is used to display the title of the app. Create a components folder. Inside it, create a Header.js file and add the following:

This is just a basic React Native component, with some styling to match the UI of our app.

Score Component

Next is the component for displaying the score (components/Score.js):

Again, just a simple display component with a text view and some basic styling.

Card Component

The card component (components/Card.js) will display the cards. These cards use icons from the Expo vector icon set. This is one of the features that come right out of the box when you use Expo: it includes icons from icon sets like FontAwesome, Entypo, and Ionicons.

In the code below, you can see that we're only using FontAwesome. It has the icon that we want for displaying the card's default state: a question mark. As you'll see later in the main app component, we'll also be using icons from Entypo and Ionicons. The reference to those icon sources will be passed to this component, so there's no need to specify them here:

Inside the render() method, we only use the source and icon passed as props if the card is opened. By default, it will only display the question mark icon from FontAwesome. But if the card is open, it will use the icon source, icon, and color that were passed as props.

Each of the cards can be tapped. When tapped, the clickCard() function will be run, which is also passed via the props. Later on you'll see what the function does, but for now, just know that it updates the state to reveal the icon on the card:

Don't forget to add the styles:

Helpers

We'll also be using a helper function called shuffle() . This allows us to sort the array of cards in random order so that their order will be different every time the game is reset:

Main Component

The main component (App.js) contains the main app logic and brings everything together. Start by including the React and Expo packages that we will be using. This time we're using all of the icon sources from Expo vector icons:

Next, include the components and the helper that we created earlier:

Inside the constructor, we first create the array which represents the unique cards. src is the icon source, name is the name of the icon (you can find the names on GitHub if you want to use other icons), and color is, naturally, the color of the icon:

Note that instead of directly specifying the src as FontAwesome , Entypo or Ionicons for each of the objects, we're using the property names used in the sources object. This is because we will need to create a copy of the array of cards in order for each card to have a pair. Creating a copy using array methods such as slice() will create a copy of the array, but the problem is that once the individual objects are modified in either the copy or the original, both arrays are also modified.

This brings us to the solution below which is to create a completely new object by converting the cards array into a string and then parsing it to convert it back to an array. This is the reason why we're using strings since functions can't be converted into strings. We then combine the two to come up with the array, which contains all the cards that we need:

Next, go through that array and generate a unique ID for each one, set the icon source, and then set it to a closed state by default:

Sort the cards randomly and set the default state:

The render() method renders the header, cards, score, and the button for resetting the current game. It's using the renderRows() function to render the individual card rows. The screen will have six rows containing four cards each:

Here's the code for the renderRows() function. This uses the getRowContents() function, which is responsible for creating an array of arrays with four items each. This allows us to render each row, and then use another function for rendering cards for each iteration of the map() function:

Here's the getRowContents() function:

Next is the renderCards() function. This accepts the array of card objects and renders them via the Card component. All we need to do here is to pass the individual properties of each card object as props. This is then used to render the correct icon, as you've seen in the code for the Card component. The clickCard() function is also passed as a prop. The card ID is passed to that function so that the unique card can be identified and updated:

Inside the clickCard() function, we get the details of the selected card and check if it should be processed any further:

Now let's fill in the code for handling a selected card.

First, we open the card and add it to the array of currently selected cards:

Once there are two items in the array of currently selected cards, we check if the icon names are the same. If they are then it means that the user has selected the correct pair. If they are not the same then it's an incorrect pair. In that case, we close the first card that was selected and then add a bit of delay before closing the second card. (This way the user can see the card icon before it reverts to the closed state.)

The last thing we need to do in the click event handler is to update the state to reflect the changes in the UI:

A related function is the reset event handler. When the reset button is tapped, we simply restore the default state by closing all the cards and shuffling.

Finally, we'll add a few basic styles to make our app look good.

Test the App

Since your Expo development server has been running this whole time, every change should be pushed to your mobile device with live reloading. Try the app out and make sure it works as it's supposed to.

Conclusion

That's it! In this tutorial you've learned how to use the Expo XDE to quickly wire up a React Native app. Expo is a really good way to start developing React Native apps because it removes the need to install a lot of software which is often a cause of frustration, especially for beginners. It also provides tools which makes it really easy to preview the app while it's being developed. Be sure to check out the resources mentioned on the Expo website if you want to learn more.

And in the meantime, have a look at some of our other posts about React Native app development!