JavaScript in the Shallow End: Browser-Based React Native With Expo Snack

#
By Mike Davey, Senior Editor

“Learn JavaScript. Deeply,” is good advice, but jumping right into the deep end when you’re first learning to swim may not be the smartest move. In this article, we’re going to get our toes wet by editing JavaScript right in the browser with Expo Snack.

Expo Snack

Expo Snack is a web-based code editor for building shareable, runnable React Native code examples. One of the key benefits of Expo Snack is that it allows developers to collaborate with others in real-time. This is beneficial when working on a team or when seeking advice from others.

You don’t need to download anything to try Expo Snack. You don’t even need an account, but you won’t be able to save your applications without one. You can create an account at https://expo.io/signup. This will give you access to all of Expo’s features, including Snack.

Before you get started, you should be aware that all projects in Expo Snack are public.

Exploring Expo Snack

Starting Expo Snack.

Expo Snack has three main sections, with the code editor sitting in the center. It will show the contents of the file you have open at the time. The menu on the left shows our project files. On the right, you have various options for running and testing your app.

Directories and Files

Click on any file or directory to view it. For example, opening the package.json file allows you to view dependencies. At the moment, it should look like this:

{
  "dependencies": {
    "react-native-paper": "4.9.2",
    "@expo/vector-icons": "^13.0.0",
    "expo-constants": "~14.0.2"
  }
}

You can create new directories or files by clicking on the icons to the right of “Project files.” You can also import files or GitHub repos. You can reorganize the files by clicking and dragging.

Emulators

The right hand section of the screen gives you access to four tabs: “My Device”, “iOS”, “Android”, and “Web”. You’ll see the “Web” tab first. Click on iOS or Android to see what the app should look like on those devices. “My Device” gives you a QR code that can be used with Expo Go to run the app on your Android device. This feature does not work with iOS, so Expo instead recommends using the “Share → Send Link” button in Expo XDE to send your device a link to the project.

Using Expo Snack

You can modify the code for the default app, import a project from GitHub, or build something entirely from scratch. In this section, we assume you’re creating an app from the ground up. For testing purposes, we’re going to create a very simple app called Steamed Hams. It will consist of a background image, some text, and a single button. When a user presses the button, the app plays a short gif. Pressing the button again gives them a short inspirational message.

Chalmers discovers the app is named "Steamed Hams", rather than "Steamed Clams," which is what he was told originally.

You don’t really have to start completely from scratch. Regardless of what you’re building, you’re probably going to want to leave the two lines at the top, giving you access to React and React Native.

If you leave them in place, you’ll probably want to modify them to suit your own purposes. Expo Snack’s React Native import starts with Text, View, and StyleSheet

The “Steamed Hams” app is going to need a button, a way to display images, and something to make sure the images are displayed at the right scale. This calls for adding Image, TouchableOpacity, and Dimension components to the React Native import.

The app also needs the useState and useEffect hooks from React so it can track how many times the button has been pressed and trigger effects at the right time.

import React, { useState, useEffect } from "react";
import { StyleSheet, Image, View, TouchableOpacity, Text, Dimensions } from "react-native";

You can import additional libraries and packages in exactly the same way. It should be noted that some libraries will not work on Snack, even if they work just fine when you’re using a CLI. This is due to differences in how the code is bundled.

One of the really neat things about Expo Snack is how it handles dependencies. When you import anything that isn’t already defined in package.json, you’ll get a warning with a button that allows you to add it. Clicking Add dependency will add it automatically, and prompt for further dependencies it needs.

Importing Assets

Expo Snack allows you to import assets locally, or use network files. In this case, it’s probably best to just have everything local to the project files. The Steamed Hams app really only needs two assets: a background image for when the user opens the app, and a gif that plays when they click the button for the first time. Clicking the three dots in the “Project” menu opens a dropdown that lets you import files, import a GitHub repo, or export your project. The last option is only live if you’re signed in.

You can go ahead and delete the snack-icon.png file found in assets, as we won’t be using it. You can also delete AssetsExample.js from components for the same reason.

import backgroundImage from './assets/skinnerBackground.jpeg';
import gifImage from './assets/imPooped.gif';

Setting Constants

The app needs to know for how long to play the gif file. There are ways to do this dynamically, but they’re more complicated than is needed here. There’s only one gif to play, and the length is predetermined at 9.28 milliseconds, so it can be declared in the file:

const gifDuration = 9280;

Functions and Variables

The next part is where the app really runs, starting with export default function App(), and following that up with variables to control the Steamed Hams UI:

export default function App() {
 const [showGif, setShowGif] = useState(false);
 const [showText, setShowText] = useState(false);
 const [isGifPlayed, setIsGifPlayed] = useState(false);

Next, the app needs a function to render the background image and button. The button function is handled by TouchableOpacity. Depending on your goals, you might be better off with Pressable instead, as it’s “more extensive and future-proof.”

const renderMainView = () => (
   <View style={styles.container}>
     {/* Display the background image */}
     <Image style={styles.backgroundImage} source={backgroundImage} />
     <TouchableOpacity style={styles.button} onPress={handleButtonClick}>
       <Text style={styles.buttonText}>STEAMED HAMS!</Text>
     </TouchableOpacity>
   </View>
 );

Next, the app needs a function to render the gif, and another function to handle the button click events. This will have to show the gif the first time the button is pressed, and show the user our inspirational text message the second time it’s pressed. This is where useEffect comes in. The app uses it to reset the state after the gif has finished playing, hiding the gif and setting the isGifPlayed state to true.

 const renderGif = () => <Image style={styles.gif} source={gifImage} />;

 const handleButtonClick = () => {
   // Show the gif if it's not played yet
   if (!showText && !isGifPlayed) {
     setShowGif(true);
   }
   // Show the text message if the gif has played once
   else if (!showText && isGifPlayed) {
     setShowText(true);
   }
 };

 useEffect(() => {
   if (showGif) {
     const timer = setTimeout(() => {
       setShowGif(false);
       setIsGifPlayed(true);
     }, gifDuration);

     return () => clearTimeout(timer);
   }
 }, [showGif]);

The app still needs a way to render the components in a return statement. The code below accomplishes this, rendering our background image and button when the app starts, rendering the gif when the showGif is true, and rendering the inspirational text message when showGif is false and showText is true. Finally, the app uses Dimensions to ensure the images are scaled appropriately.

 return (
   <View style={styles.container}>
     {!showGif && !showText && renderMainView()}
     {showGif && !showText && renderGif()}
     {showText && (
       <View style={styles.textContainer}>
         <Text style={styles.mainText}>
           That's enough cartoons for one day. Go outside and do some isometric exercises.
         </Text>
       </View>
     )}
   </View>
 );
}

const windowDimensions = Dimensions.get('window');

Styling Your Components

Styling in React Native is very similar to CSS, but with a few differences. As a rule of thumb, use camelCase where you would normally use a hyphenated expression. For example, background-color in CSS translates to backgroundColor in React Native.

const styles = StyleSheet.create({
 container: {
   flex: 1,
   justifyContent: 'center',
   alignItems: 'center',
   overflow: 'hidden',
 },
 backgroundImage: {
   width: windowDimensions.width,
   height: windowDimensions.height,
   resizeMode: 'contain',
 },
 button: {
   backgroundColor: 'blue',
   paddingHorizontal: 20,
   paddingVertical: 10,
   borderRadius: 5,
   position: 'absolute',
   bottom: '25%',
 },
 buttonText: {
   color: 'white',
   fontSize: 18,
 },
 gif: {
   width: windowDimensions.width,
   height: windowDimensions.height,
   resizeMode: 'contain',
 },
 textContainer: {
   flex: 1,
   justifyContent: 'center',
   alignItems: 'center',
   backgroundColor: 'black',
 },
 mainText: {
   fontSize: 36,
   color: 'white',
   textAlign: "center"
 },
});

That’s all that’s necessary to create a simple app with Expo Snack. If you’re interested in forking and modifying Steamed Hams, you can do so here.

Conclusion

Learning React Native will greatly expand what you can do in WordPress, but it can be difficult to dedicate the time needed for complete mastery. Dipping your toes into the shallow end may be a better way to get started than diving in head first.

Have you built anything with Expo Snack, or another online “sandbox” code editor? Let us know in the comments or on Twitter.

About the Author

Mike Davey Senior Editor

Mike is an editor and writer based in Hamilton, Ontario, with an extensive background in business-to-business communications and marketing. His hobbies include reading, writing, and wrangling his four children.