In this episode, we will improve the layout of our application. So far, our application does its job, but it's not beautiful.

In React Native, we have some libraries to help us improve the design. There are NativeBase and React Native Elements. If you know others, let us know!

We are going to use React Native Elements. It provides us a series of ready-made buttons, components,typography, fonts and icons. It's very beautiful.

We will use their quickstart app and move our app to this standard. This is the quickstart app, and it's pretty good. It has some good examples we can use.

Let's check the code! This is the final result we got. As you can see, it's better than before.

First of all, we haved cloned the quickstart app.

We're going the two have screens from the last episode, and we will stick with the tab bar layout. We have added a new screen called About.

We have removed the screens we were not using and we're left with just three screens:

  • ListDocs
  • DetailsDocs
  • About

Those changes will reflect on our App.js:

      <Tabs hidesTabTouch>
        <Tab
          titleStyle={[styles.titleStyle]}
          selectedTitleStyle={[styles.titleSelected, {marginTop: -3, marginBottom: 7}]}
          title={selectedTab === 'listdocs' ? 'DOCS' : null}
          tabStyle={selectedTab !== 'listdocs' && { marginBottom: -6 }}
          selected={selectedTab === 'listdocs'}
          renderIcon={() => <Icon style={{paddingBottom: 4 }} color={colors.grey2} name='list' size={26} />}
          renderSelectedIcon={() => <Icon color={colors.primary} name='list' size={26} />}
          onPress={() => this.changeTab('listdocs')}>
          <ListDocs changeTab={this.changeTab} selectItem={this.selectItem} />
        </Tab>

        <Tab
          selected={selectedTab === 'detailsdocs'}
          onPress={() => this.changeTab('detailsdocs')}>
          <DetailsDocs itemContent={itemContent} changeTab={this.changeTab} />
        </Tab>

        <Tab
          titleStyle={[styles.titleStyle, {marginTop: -1}]}
          selectedTitleStyle={[styles.titleSelected, {marginTop: -3, marginBottom: 7}]}
          title={selectedTab === 'about' ? 'ABOUT' : null}
          tabStyle={selectedTab !== 'about' && { marginBottom: -6}}
          selected={selectedTab === 'about'}
          renderIcon={() => <Icon style={{paddingBottom: 4 }} color={colors.grey2} name='question-answer' size={26} />}
          renderSelectedIcon={() => <Icon color={colors.primary} name='question-answer' size={26} />}
          onPress={() => this.changeTab('about')}>
          <About />
        </Tab>

      </Tabs>

We have each screen as a Tab. It does not have an icon, so it does not appear for us. Visually, we will just see two tabs on the bottom.

To change the screens we are using the function:

  changeTab (selectedTab) {
    this.setState({
      selectedTab
    })
  }

The way the app is structured is similar to what we saw in our episodes. It allows us to use redux and it has containers connecting to Redux. So, it's up to you whether to use redux or not. For each screen, there is theScreen, containing the necessary tags to show the component, theScreenNav for Navigation purposes and theScreenRootContainer, to be used to connect with Redux.

With this in mind, our screens will follow this standard. We found this standard interesting. Redux is not connected, but it has all the structure to be used. This will be one exercise. Add redux to this app.

Let's take a look at our About screen:

import React, { Component } from 'react'
import { ScrollView, View, StyleSheet, Image } from 'react-native'
import colors from 'HSColors'
import Icon from 'react-native-vector-icons/MaterialIcons'

import {
  Card,
  Button,
  Text
} from 'react-native-elements'

let styles = {}

class About extends Component {
  render () {
    return (
      <ScrollView style={{backgroundColor: 'white'}}>
        <View style={styles.headingContainer}>
          <Image source={require('../images/dailydrip.png')} />
          <Text style={styles.heading}>About</Text>
        </View>
        <View style={styles.container}>
        <Card
            title='Contribute with us'>
            <Text style={{marginBottom: 10}}>
              This project is totally open source by DailyDrip.
            </Text>
            <Button
              icon={{name: 'code'}}
              backgroundColor='#03A9F4'
              buttonStyle={{borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}}
              title='Check the code' />
          </Card>
        </View>
      </ScrollView>
    )
  }
}

styles = StyleSheet.create({
  container: {
    margin: 15
  },
  headingContainer: {
    marginTop: 60,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 40,
    backgroundColor: colors.grey2
  },
  aboutImage: {
    height: 19.21,
    width: 100
  },
  heading: {
    color: 'white',
    marginTop: 10,
    fontSize: 22
  }
})

export default About

Button and Card components are from React Native Elements. They are very handy! It has other components for forms, lists, icons, etc.

We are using our API file and using the same functions as before, so not a lot of changes for this part.

Once we click on an item, we will need to call the function changeTab. The function changeTab is in our App component. We need it on the component ListDocs, so we will need to pass this function to the other components. Also, inside the DetailsDocs we will need to get the item content and render it. To do that, we will make the API request in our top-level component, App and then we will make just the content to our stateless ListDocs components, with this our ListDocs component will just show the result of the received props.

  selectItem(item){
    this.setState({item})
    this.getContent(item)
  }

  getContent(item) {
    API.getDocsContent(item)
    .then((response) => {
      console.log(response)
      this.setState({
        itemContent: response
      })
    })
    .catch((err) => {
      console.error(err)
    })
  }

In our ListDocs we will need to set the Item, also change the Tab. So, we are passing these functions to the component as props:

<ListDocs changeTab={this.changeTab} selectItem={this.selectItem} />

And in the component, on the onPress we update the Item.

class ListDocs extends Component {

  pressItem(itemName) {
    this.selectItem(itemName)
    this.changeTab('detailsdocs')
  }

  constructor (props) {
    super(props)
    this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})

    this.state = {
      dataSource: this.ds.cloneWithRows(list1)
    }
    this.changeTab = props.changeTab
    this.selectItem = props.selectItem
    this.renderRow = this.renderRow.bind(this)
    this.pressItem = this.pressItem.bind(this)
  }
  renderRow (rowData) {
    var navigator = this.props.navigator
    return (
      <ListItem
        onPress={() => this.pressItem(rowData)}
        title={rowData}
      />
    )
  }

  componentWillMount(){
    API.getDocsList()
    .then((response) => {
      console.log(response)
      this.setState({
        dataSource: this.ds.cloneWithRows(response)
      })
    })
    .catch((err) => {
      console.error(err)
    })
  }
  render () {
    return (
      <ScrollView keyboardShouldPersistTaps="always" style={styles.mainContainer}>
        <List>
          <ListView
            renderRow={this.renderRow}
            dataSource={this.state.dataSource}
            />
        </List>
      </ScrollView>
    )
  }
}

At our DetailsDocs we just need to pass the item content. DetailsDocs is a stateless component.

<DetailsDocs itemContent={itemContent} />

And if we check our DetailsDocs it's very simple. We just get the item content and we render it inside the scrollview.

const DetailsDocs = (props) => {
  return (
    <ScrollView keyboardShouldPersistTaps="always" style={styles.mainContainer}>
      <Text> { props.itemContent } </Text>
    </ScrollView>
  )
}

So far, we are just showing the pure markdown. In another episode, we will improve this part.

React Native Elements helped us create a beautiful interface for our app and now our app is even better than before.