Flexbox layouts and lists with React Native

Posted by

Introduction

This tutorial is all about using Flexbox layout in React Native. I will show you an in-depth example of taking a wireframe and extracting it into a set of React Native components and then styling them with Flexbox so that they match what was designed in the wireframe (in Sketch). I will also be covering the new FlatList in React Native, which is the preferred way to create lists.

I won’t be covering React Native basics, for that please refer to my Getting Started with React Native tutorial.

What you will learn in this tutorial

You can learn more about the basics of Flexbox in this tutorial, and here on Mozilla Developer Network. In this tutorial, I will take you thru the process of dissecting a wireframe and turning into React Native components, and using styling to make the UI match the high fidelity mockups you might get from your design team.

I will also walk you thru the new FlatList component that is part of React Native. It’s a very powerful API and it’s very elegant and simple to use, yet, it’s very expressive and powerful – what’s not to like!

Get the project from GitHub

We are going to use this fake weather app that I’ve created, along with the help of Maret Eiland – she’s a designer who can talk to developers :). You can download the source code and run the project on your local development environment.

Here’s what the app looks like on Android:

Here’s what the app looks like on iOS:

Wireframe -> Flexbox layout -> code

Before we get started on the process, here are the 3 main screens of the weather app that we are using. You can find these screens in this Sketch file here.

wireframes.png

Each screen of this app contains a FlatList with a row renderer and some styling. I will take you thru the process of generating the first screen that shows a list of places with the current temperature and current conditions icon. Once you see how the first screen is created, the other two screens are very simple to create.

Going from wireframe to Flexbox

The wireframes from Sketch contain a picture of the desired UI. This is what your design team might hand you. The task of converting this picture into React components with styling is our challenge. The best way to think about this is to:

  • Start cutting your wireframe into boxes that map to React components.
  • Think about how these components are composed. They are probably going to be nested somehow. There are going to be parent components (containers) which will contain children components. These children might also be containers for other components in this hierarchy.

Let’s use a real example of the Home screen of our app. It has a header (icon and Weather app) that is provided by the Stack Navigator. So we can ignore this. We are most interested in the list view that contains places and current temperature information. This list view is going to be built using a FlatList, since this is the new and better way of doing things.

The way FlatList works is that it takes some data, and it takes a row renderer which will handle the task of rendering or painting each row to the screen. FlatList also takes care of it’s own scrolling, and you can even set the layout direction (horizontal or vertical). Additionally, flex:1 is set on the FlatList by default and you can’t really change that.

Going from FlexBox to code

If you look at the diagram below, it visually depicts how we break the Home screen into a FlatList, then apply styling to the FlatList and then map that into React components that we add to our JSX.

react native design V1.002.png

This is the code for the JSX you see on the right of the image:

<View style={css.home_screen.v_container}>
  <StatusBar ... />

  <FlatList
          style={css.home_screen_list.container}
          data={listData}
          renderItem={this.renderRow}
  />

</View>

Here are more details on the styling (from Styles.js):

There’s a v_container style that’s set for a View, which acts as the main container for the entire screen. It sets the background color to a light gray color and sets up the flex box container and main axis and cross axis alignment options.

export const home_screen = StyleSheet.create(
  {
    v_container: {
      flex: 1,
      padding: 8,
      flexDirection: 'column', // main axis
      justifyContent: 'center', // main axis
      alignItems: 'center', // cross axis
      backgroundColor: colors.background_dark,
    },
  });

Here are more details on the JSX (from HomeScreen.js):

Inside of the View we have a StatusBar component for Android (ignore this for now). The main thing inside of this View is the FlatList component. This component is created with:

  • The dummy data (more in this later in this tutorial).
  • The style for the FlatList itself.
  • The renderItem function that will be used to render each row of the data.

Here’s the styling for the FlatList:

container: {
  marginTop: 14,
  alignSelf: "stretch",
}

The renderRow function

The heavy lifting of doing React component composition with Flexbox really happens in the renderRow function which we will deep dive into now.

renderRow({item}) {

  const time = `${item.time}`;
  const place = `${item.place}`;
  const temp = css.addDegreesToEnd(item.currentTemp);
  const {iconName, iconFont, iconColor} = item.icon;

  let actualRowComponent =
    <View style={css.home_screen_list.row}>
      <View style={css.home_screen_list.row_cell_timeplace}>
        <Text style={css.home_screen_list.row_time}>{time}</Text>
        <Text style={css.home_screen_list.row_place}>{place}</Text>
      </View>
      <Icon color={iconColor} size={css.values.small_icon_size} name={iconName}
            type={iconFont}/>
      <Text style={css.home_screen_list.row_cell_temp}>{temp}</Text>
    </View>;

  ...

}

Here’s the styling code that goes along with this code.

export const home_screen_list = StyleSheet.create(
  {
    container: {
      marginTop: 14,
      alignSelf: "stretch",
    },
    row: {
      elevation: 1,
      borderRadius: 2,
      backgroundColor: colors.tertiary,
      flex: 1,
      flexDirection: 'row',  // main axis
      justifyContent: 'flex-start', // main axis
      alignItems: 'center', // cross axis
      paddingTop: 10,
      paddingBottom: 10,
      paddingLeft: 18,
      paddingRight: 16,
      marginLeft: 14,
      marginRight: 14,
      marginTop: 0,
      marginBottom: 6,
    },
    row_cell_timeplace: {
      flex: 1,
      flexDirection: 'column',
    },
    row_cell_temp: {
      color: colors.weather_text_color,
      paddingLeft: 16,
      flex: 0,
      fontSize: values.font_temp_size,
      fontFamily: values.font_body,
    },
    row_time: {
      color: colors.weather_text_color,
      textAlignVertical: 'bottom',
      includeFontPadding: false,
      flex: 0,
      fontSize: values.font_time_size,
      fontFamily: values.font_body,
    },
    row_place: {
      color: colors.weather_text_color,
      textAlignVertical: 'top',
      includeFontPadding: false,
      flex: 0,
      fontSize: values.font_place_size,
      fontFamily: values.font_body,
    },
  });

The following diagram shows what is happening in this renderRow function.

react native design V1.003.png

Here are the steps that have to happen going from the picture of a row in the wireframe (on the left) to the code on the right:

  • Each row of the FlatList is comprised of some data that has to be displayed. We extract this data from the {item} JSON object that’s passed to the renderRow function from the FlatList. From this {item} object, we get the time, place, currentTemperature, and icon. The values from these objects are then used in the React components nested in the JSX code.
  • There’s a container View that is styled with the home_screen_list.row style. This basically creates a horizontal container which will hold all the other components inside of it. There are 3 React components that are nested inside of this container:
    • View that holds the 2 Text components that display the time and place info, that are stacked vertically. The home_screen_list_row_cell_timeplace sets this container up. flex:1 is set on this container, and it takes up all the horizontal space that’s available, so that the icon and temperature Text components can be slammed to the right of the row. This creates the space that you see in the UI. weatherapp-MainActivity-04262017141529
    • Icon that displays the font icon. No flex value is set for this component, so it takes up its preferred height and width.
    • Text that displays the temperature value with styling home_screen_list.row_cell_tempflex:0 value is set for this component, so it takes up its preferred height and width.
  • The FlatList them stamps out each row of the data that’s provided to it, and renders the UI that you see in the app for HomeScreen.js.
  • In the code, there’s some platform specific code that uses a TouchableHighlight on iOS or TouchableNativeFeedback on Android to wrap each list row. When a user touches each list row, it uses the _navigation object in order to push the appropriate route into the Navigator.

 

Best practices for collaborating with your design team

Whew! That has been a deep dive into how to go from wireframes -> flexbox -> code in React Native. You can engage your design team in this process as well, since they can provide you with:

  • Feedback on how to actually create the styles (what values to set for padding, margin, size of the icons, colors, and so forth).
  • Organize the layouts in your code using Flexbox. Since they constructed the wireframes, they have a vision in their minds of how the UI should actually function. Currently they give developers a picture of a thing, and not the actual thing. Developers are then responsible for taking the picture and making the thing. And lots falls apart in this collaboration today.

It is also important for your design team to understand the basics of Flexbox so that they can understand how to structure their thinking when assembling the wireframes themselves. All too often, designs get ‘shipped’ from design to development and there isn’t a good way for designers to communicate with developers, so that their designs can come to life in the way that was intended by them.

Data driven design

Our fake weather app is fake because it actually doesn’t hook into a live data source for it’s information. However, the app is constructed in a way that it should be possible to swap out this fake data pipeline for a real one (that’s coming from a web service). I’m going to release a tutorial very soon with this app using real weather data, Firebase, and even social SignIn, so please stay tuned for that.

The fake data in our app comes from Data.js. This is a JSON object that holds an array of objects for the FlatList component. Each item in this array is an object that holds information about a place:

  • place name,
  • time,
  • icon,
  • current temperature,
  • description,
  • an array of objects holding today’s forecast (called dailyForecast),
  • an array of objects holding this week’s forecast (called weeklyForecast).

I showed you in depth how the HomeScreen.js is built, and how it leverages a FlatList to render this list of data. When the user clicks on a row in the list, React Navigation is used (Router.js) in order to push the user selection of place, and then provide views that display today’s forecast, and the week’s forecast.

Working with data in this manner to prototype the app’s UI and interaction is really good practice, and I recommend it strongly. I even recommend that you engage with your designers and get them to start with data as well, and consult with development teams to determine if certain types of data can be accessed by your app.

React Native resources

React, Redux, and native Android resources