Add a JSX UI Component to Your App

Let’s add a React Native JSX component to your app.

Add a React Native Component

Add a Simple Button

Open MyApp/index.youi.js in your editor and import the Button component from React Native.

diff --git a/before/index.youi.js b/after/index.youi.js index 28764fe..28ea884 100644 --- a/before/index.youi.js +++ b/after/index.youi.js @@ -2,7 +2,7 @@ import React, { Component } from "react"; -import { AppRegistry, Image, SafeAreaView, StyleSheet, Text, View } from "react-native"; +import { AppRegistry, Button, Image, SafeAreaView, StyleSheet, Text, View } from "react-native"; import { FormFactor } from "@youi/react-native-youi"; export default class YiReactApp extends Component {

Add a simple button press handler onMyButtonPress above the render function.

diff --git a/before/index.youi.js b/after/index.youi.js index 28ea884..f116c66 100644 --- a/before/index.youi.js +++ b/after/index.youi.js @@ -6,6 +6,11 @@ import { AppRegistry, Button, Image, SafeAreaView, StyleSheet, Text, View } from "react-native import { FormFactor } from "@youi/react-native-youi"; export default class YiReactApp extends Component { + onMyButtonPress = () => { console.log("***** You keep pressing my buttons. Stop it! *****"); }; + render() { return ( <SafeAreaView style={styles.mainContainer}>

Make use of the new button handler by adding a button to your app. Create a new View below the View Image is contained within. Give it the style buttonContainer (we’ll create that in a moment). In this view, add the button with a title and an onPress handler.

diff --git a/before/index.youi.js b/after/index.youi.js index f116c66..80596e8 100644 --- a/before/index.youi.js +++ b/after/index.youi.js @@ -28,6 +28,12 @@ export default class YiReactApp extends Component { source={{ uri: "res://drawable/default/my-new-image-file.png" }} /> </View> <View style={styles.buttonContainer}> <Button onPress={this.onMyButtonPress} title="My button" /> </View> </View> <View style={styles.bodyContainer} focusable={true} accessible={true}> <Text

Now, add the buttonContainer style to the Stylesheet defined at the bottom of index.youi.js.

diff --git a/before/index.youi.js b/after/index.youi.js index 80596e8..2ae9b84 100644 --- a/before/index.youi.js +++ b/after/index.youi.js @@ -80,6 +80,11 @@ const styles = StyleSheet.create({ width: FormFactor.isTV ? 225 : 75, resizeMode: "contain" }, buttonContainer: { flex: 1, justifyContent: "center", alignItems: "center" }, bodyContainer: { alignItems: "center", justifyContent: "center",

Add Accessibility Features

Like Facebook RN apps, You.i Platform apps can be made accessible. You can add accessibility information to your app to support screen reading functionality.

Let’s go back to the button you added earlier and update it with accessibility props.

          <View style={styles.buttonContainer}
            focusable={true}
            accessible={true}
            accessibilityLabel="My button"
            accessibilityHint="Button in your first app"
            accessibilityRole="button"
          >
            <Button
              onPress={this.onMyButtonPress}
              title="My button"
              />
          </View>

See the Button in Your App

Run your application again to see the button you just added.

There’s not much to the button yet, but you’ll remember that we added a button handler. Try clicking it a few times.

Now, switch back to the terminal window you used to launch your app. Review the console log output to see if you can find your button handler’s log messages.

***** You keep pressing my buttons. Stop it! *****

The log messages tell us that your new button is working. If you don’t see the log messages, double-back and check your work before moving on.

Add a Custom Component

Next, let’s add a bit of fun to the application by adding a light and dark mode. To do this, we’ll make use of a new custom Button component and a couple more styles.

Here’s a quick GIF demonstrating what we’re going to build.

Animated GIF showing the background and text changing color and content when the button is pressed in your first You.i React Native application

Keep Track of Mode (Light or Dark)

Let’s use a state variable to track the current theme state: light or dark. Add the lightTheme variable to your app as shown below.

We want the app to change from dark to light mode (or vice versa) whenever the button is pressed. After adding the state, modify the onMyButtonPress handler to reverse the state of lightTheme. And while we’re in there, let’s make it print a more useful log message.

...
export default class YiReactApp extends Component {
  state = {
    lightTheme: true
  };
  onMyButtonPress = () => {
    this.setState({
      lightTheme: !this.state.lightTheme
    });
    console.log('***** Changing theme to: ' + (this.state.lightTheme ? 'dark' : 'light' ) + ' *****');
  };

Update the Button Text Based on the Theme

Until now, our button’s label has been My Button (unless you got more creative with yours). Let’s update the button to indicate what it does when it’s pressed.

Start by destructuring lightTheme from the state.

  render() {
    const { lightTheme } = this.state;

Then, use this value to update the button’s title to reflect the expected result of pressing it.

  return (
    ...
    <Button
      onPress={this.onMyButtonPress}
      title={`Switch to the ${lightTheme ? "dark" : "light"} theme`}
    />
    ...
}

Give it a test. Switch back to your app and click the button a few times. With each click, the button text changes. And your console log messages now reflect the theme mode changes.

Add a Style Sheet and a Custom Button

To simplify making a dark and light theme, we have a custom style sheet with the colors already defined. Copy and paste the following definitions into a new file called styles.js, in the same location as index.youi.js.

import { StyleSheet } from "react-native";

export const darkStyles = StyleSheet.create({
  header: {
    backgroundColor: "#000000"
  },
  button: {
    backgroundColor: "#f1f1f1"
  },
  buttonText: {
    color: "#000000"
  },
  body: {
    backgroundColor: "#303030"
  },
  headlineText: {
    color: "#f1f1f1"
  },
  bodyText: {
    color: "#f1f1f1"
  }
});

export const lightStyles = StyleSheet.create({
  header: {
    backgroundColor: "#ffffff"
  },
  button: {
    backgroundColor: "#333333"
  },
  buttonText: {
    color: "#ffffff"
  },
  body: {
    backgroundColor: "#e6e7e7"
  },
  headlineText: {
    color: "#333333"
  },
  bodyText: {
    color: "#333333"
  }
});

We’ve also created a custom Button component. Our new Button includes a default focus state that we’ll make use of as we build out the theme mode. Copy and paste the following into a new file called button.js in the same folder as index.youi.js and styles.js.

import React from "react";
import { StyleSheet, Text, TouchableWithoutFeedback, View } from "react-native";
import { FocusManager } from "@youi/react-native-youi";

const Button = ({
  buttonStyle,
  defaultFocus,
  onPress,
  textStyle,
  title
}) => {

  return (
    <TouchableWithoutFeedback
      focusable={true}
      accessible={true}
      accessibleLabel={title}
      onPress={onPress}
      ref={ref => ref && defaultFocus && FocusManager.focus(ref)}
    >
      <View style={[styles.button, buttonStyle]}>
        <Text style={[styles.buttonText, textStyle]}>{title}</Text>
      </View>
    </TouchableWithoutFeedback>
  );
};

const styles = StyleSheet.create({
  button: {
    paddingHorizontal: 30,
    paddingVertical: 10,
    borderRadius: 5
  },
  buttonText: {
    fontSize: 20
  }
});

export default Button;

Hook up the New Button

Modify index.youi.js to import the new custom Button component and the style sheets you just created in styles.js. Be sure to remove the previous react-native Button import.

import React, { Component } from "react";
import { AppRegistry, Image, SafeAreaView, StyleSheet, Text, View } from "react-native";
import { FormFactor } from "@youi/react-native-youi";
import Button from './button.js';
import { lightStyles, darkStyles } from './styles.js';
...

Let’s configure Button to get both the button’s style and associated button text style from our new style sheets. Add two new props, textStyle and buttonStyle to Button in index.youi.js. Configure these so they set the button’s styling based on the currently selected theme.

While you’re in there editing Button, you can also update it to use the defaultFocus prop. To give the button focus when the app starts, set defaultFocus to true.

The new button component in your app looks like this:

 render()
 ...
            <Button
              onPress={this.onMyButtonPress}
              title={`Switch to the ${lightTheme ? "dark" : "light"} theme`}
              textStyle={lightTheme ? lightStyles.buttonText : darkStyles.buttonText}
              buttonStyle={lightTheme ? lightStyles.button : darkStyles.button}
              defaultFocus={true}
            />

If your application is already running, when you save these changes the application will refresh automatically.

At this point, your application should look like this. When you press the button, the text and style change. Next, we’ll add in the rest of the dark theme.

Your application as a work in progress

Apply the Dark Theme

To implement the theme switch, we’ll use a function that provides the name of the style sheet to use (lightStyles or darkStyles). Add a new getTheme function near the bottom of index.youi.js.

   ...
   });

   function getTheme(lightTheme) {
     return lightTheme ? lightStyles : darkStyles;
   }

   AppRegistry.registerComponent("YiReactApp", () => YiReactApp);

Configure the Button Styles

Before rendering, the app can check which style to apply, by calling your new function. In your main render() function, add a new constant themeStyles that retrieves the current theme.

     render() {

       const { lightTheme } = this.state;
       const themeStyles = getTheme(lightTheme);

       return (
   ...

Now, update headerContainer, bodyContainer, headlineText, and bodyText to use a combination of the original style and the current theme style (themeStyles.<x>) as shown below.

   return (
       <SafeAreaView style={styles.mainContainer}>
         <View style={[styles.headerContainer, themeStyles.header]}>
...
       <View style={[styles.bodyContainer, themeStyles.body]} focusable={true} accessible={true}>
         <Text
           style={[styles.headlineText, themeStyles.headlineText]}
           accessibilityLabel="Welcome to your first You I React Native app"
         >
           Welcome to your first You.i React Native app!
         </Text>
         <Text
           style={[styles.bodyText, themeStyles.bodyText]}
         >
           For more information on where to go next visit
         </Text>
         <Text
           style={[styles.bodyText, themeStyles.bodyText]}
           accessibilityLabel="https://developer dot you i dot tv"
         >
           https://developer.youi.tv
        </Text>
      </View>
...

If you kept your own logo in the app instead of the You.i TV logo, get a “dark mode” copy of that logo and put it in <AppName>/youi/AE/assets/drawable/default.

If you’re using the You.i TV logo, right-click and download this You.i TV dark mode logo. Save it in <AppName>/youi/AE/assets/drawable/default/.

Update index.youi.js to be aware of both versions of your image (lightImage and darkImage). Then alter Image’s source to change the picture dynamically, by selecting the correct image based on the theme. Remember to use your file names if not using the You.i TV logo.

  render() {

    const { lightTheme } = this.state;
    const themeStyles = getTheme(lightTheme);
    const lightImage = "youi_logo_red.png";
    const darkImage = "youi_logo_white.png";

  ...
    <Image
      style={styles.image}
      source={{ uri: `res://drawable/default/${lightTheme ? lightImage : darkImage}` }}
    />
...

You’ve added a new asset, so you need to rebuild your application to get the new image copied into your target folder.

youi-tv build -p osx
youi-tv build -p linux
youi-tv build -p win64

Then run your app again to see the full dark mode toggle in action!

./youi/build/osx/Debug/MyApp
./youi/build/linux/Debug/bin/MyApp
./youi/build/uwp/Debug/MyApp

Next Steps

Now you have a working app that uses basic React Native components and a custom component.

Next up, let’s take a look at some automated tests for your application.