Subscribe now

Introduction to Ignite [02.20.2017]

We have been studying React Native for the last several weeks, but we have not looked at any React Native frameworks yet. We are now familiar enough with the basics of React Native to dive into a framework. It's always good to have the basics of a technology down before looking at frameworks and libraries.

The principle of a framework is to invest in your task — not in the technology. For example, if we need to create a ListView in our app, we don't have to waste time checking how to implement that in React Native, or the best way to do so. The framework takes care of this by giving us the best and fastest solution. Also, frameworks with good communities will have updated libraries and places to ask questions. Frameworks aren’t essential, but they are very useful.

In this episode we will dive into Ignite, a React Native Framework made by Infinite Red.

Ignite includes a component generator, styles, an integration with push notification services, animations, and more. It also utilizes Javascript and React Native best practices. It is well tested, because the Infinite Red team uses it on their own projects.

Some of the interesting libraries Ignite uses:

There are also a few more libraries I have not listed. If you use Ignite, your project is already completely set up for built-in translations, tests, and you can easily create map views!

Here a basic structure of our code in a Ignite project:

├── android
├── ios
├── fastlane
├── App
  ├── Components
  ├── Config
  ├── Containers
  ├── Fixtures
  ├── i18n
  ├── Images
  ├── Lib
  ├── Navigation
  ├── Redux
  ├── Sagas
  ├── Services
  ├── Themes
  ├── Transforms
├── Tests

Have in mind, they have already divided the project into interesting points of view.

Components and Containers - Remember when we studied Stateless Components? We used a standard to show differences between smart and dumb containers. Ignite also uses the same standard.

Redux and Sagas - The redux part will be a little bit different from what we’ve done so far, because Ignite uses redux sagas rather than redux-loop. This is not a problem—we will start using sagas and learn as we go.

Themes - It's very cool to have a theme totally set up in your application – with customizable colors! Just change the colors in your palette.

Internationalization - We didn't touch on this subject before, but there is a library called react-native-i18n that allows you to easily add translations for your app.

Navigation - Ignite does not use react-navigation on the version 1, version 2 (coming soon) will use React Navigation. They use react-router-flux which we already saw in the episode about transitions between screens. This part should be familiar to you.

Talk is cheap. Let's show the code.

To install Ignite, it's very simple.

npm install -g react-native-ignite

or

yarn global add react-native-ignite

To create an application use: ignite new MyApplication.

The first time we looked at an Ignite project, you probably were surprised with the quantity of generated code. Don’t worry, they are just examples. The code will decrease once you start organizing only the parts you want to implement.

We’ll start (like always), with our index.ios/android.js. Here we are just registering the component and calling our App. Nothing different from what we already know.

// @flow

import './App/Config/ReactotronConfig'
import { AppRegistry } from 'react-native'
import App from './App/Containers/App'

AppRegistry.registerComponent('DailyDrip', () => App)

Let's check our App file. Like we saw in other projects, we start the connection with redux, and then we pass the store. The Configurations here are interesting because Ignite uses react-native-config. This gives us global configuration variables in our app.

// @flow

import React, { Component } from 'react'
import { Provider } from 'react-redux'
import '../I18n/I18n' // keep before root container
import RootContainer from './RootContainer'
import createStore from '../Redux'
import applyConfigSettings from '../Config'

// Apply config overrides
applyConfigSettings()
// create our store
const store = createStore()

/**
 * Provides an entry point into our application.  Both index.ios.js and index.android.js
 * call this component first.
 *
 * We create our Redux store here, put it into a provider and then bring in our
 * RootContainer.
 *
 * We separate it like this to play well with React Native's hot reloading.
 */
class App extends Component {
  render () {
    return (
      <Provider store={store}>
        <RootContainer />
      </Provider>
    )
  }
}

export default App

Let's check our RootContainer. Here, we start using ReduxPersist and we call our NavigationRouter. It contains all the scenes our router should have and also shows which screen is the first screen.

// @flow

import React, { Component } from 'react'
import { View, StatusBar } from 'react-native'
import NavigationRouter from '../Navigation/NavigationRouter'
import { connect } from 'react-redux'
import StartupActions from '../Redux/StartupRedux'
import ReduxPersist from '../Config/ReduxPersist'

// Styles
import styles from './Styles/RootContainerStyle'

class RootContainer extends Component {
  componentDidMount () {
    // if redux persist is not active fire startup action
    if (!ReduxPersist.active) {
      this.props.startup()
    }
  }

  render () {
    return (
      <View style={styles.applicationView}>
        <StatusBar barStyle='light-content' />
        <NavigationRouter />
      </View>
    )
  }
}

// wraps dispatch to create nicer functions to call within our component
const mapDispatchToProps = (dispatch) => ({
  startup: () => dispatch(StartupActions.startup())
})

export default connect(null, mapDispatchToProps)(RootContainer)

Our NavigationRouter is something we saw when we were studying about react-router-flux. It’s just a set of scenes in which we can set the main screen, in this case: PresentationScreen.

class NavigationRouter extends Component {
  render () {
    return (
      <Router>
        <Scene key='drawer' component={NavigationDrawer} open={false}>
          <Scene key='drawerChildrenWrapper' navigationBarStyle={Styles.navBar} titleStyle={Styles.title} leftButtonIconStyle={Styles.leftButton} rightButtonTextStyle={Styles.rightButton}>
            <Scene initial key='presentationScreen' component={PresentationScreen} title='Ignite' renderLeftButton={NavItems.hamburgerButton} />
            <Scene key='componentExamples' component={AllComponentsScreen} title='Components' />
            <Scene key='usageExamples' component={UsageExamplesScreen} title='Usage' rightTitle='Example' onRight={() => window.alert('Example Pressed')} />
            <Scene key='login' component={LoginScreen} title='Login' hideNavBar />
            <Scene key='listviewExample' component={ListviewExample} title='Listview Example' />
            <Scene key='listviewGridExample' component={ListviewGridExample} title='Listview Grid' />
            <Scene key='listviewSectionsExample' component={ListviewSectionsExample} title='Listview Sections' />
            <Scene key='listviewSearchingExample' component={ListviewSearchingExample} title='Listview Searching' navBar={CustomNavBar} />
            <Scene key='mapviewExample' component={MapviewExample} title='Mapview Example' />
            <Scene key='apiTesting' component={APITestingScreen} title='API Testing' />
            <Scene key='theme' component={ThemeScreen} title='Theme' />

            {/* Custom navigation bar example */}
            <Scene key='deviceInfo' component={DeviceInfoScreen} title='Device Info' />
          </Scene>
        </Scene>
      </Router>
    )
  }
}

The Presentation screen shows some Buttons, texts and Images, as you can see:

// @flow

import React from 'react'
import { ScrollView, Text, Image, View } from 'react-native'
import { Images } from '../Themes'
import RoundedButton from '../Components/RoundedButton'
import { Actions as NavigationActions } from 'react-native-router-flux'

// Styles
import styles from './Styles/PresentationScreenStyle'

export default class PresentationScreen extends React.Component {
  render () {
    return (
      <View style={styles.mainContainer}>
        <Image source={Images.background} style={styles.backgroundImage} resizeMode='stretch' />
        <ScrollView style={styles.container}>
          <View style={styles.centered}>
            <Image source={Images.clearLogo} style={styles.logo} />
          </View>

          <View style={styles.section} >
            <Text style={styles.sectionText} >
              Default screens for development, debugging, and alpha testing
              are available below.
            </Text>
          </View>

          <RoundedButton onPress={NavigationActions.componentExamples}>
            Component Examples Screen
          </RoundedButton>

          <RoundedButton onPress={NavigationActions.usageExamples}>
            Usage Examples Screen
          </RoundedButton>

          <RoundedButton onPress={NavigationActions.apiTesting}>
            API Testing Screen
          </RoundedButton>

          <RoundedButton onPress={NavigationActions.theme}>
            Theme Screen
          </RoundedButton>

          <RoundedButton onPress={NavigationActions.deviceInfo}>
            Device Info Screen
          </RoundedButton>

          <View style={styles.centered}>
            <Text style={styles.subtitle}>Made with ❤️ by Infinite Red</Text>
          </View>

        </ScrollView>
      </View>
    )
  }
}

On this screen, we can see some interesting aspects.

Styles

// Styles
import styles from './Styles/PresentationScreenStyle'

The screen is called PresentationScreen and the Style PresentationScreenStyle. This is the standard we are using for Screen and Styles. If we check the style file:

// @flow

import { StyleSheet } from 'react-native'
import { Metrics, ApplicationStyles } from '../../Themes/'

export default StyleSheet.create({
  ...ApplicationStyles.screen,
  logo: {
    height: Metrics.images.logo,
    width: Metrics.images.logo,
    resizeMode: 'contain'
  },
  centered: {
    alignItems: 'center'
  }
})

We are using the ApplicationStyle and adding the styles of this page. The style is not located in our component file. Interestingly, the Metrics is also located in the Themes folder. It contains all of the sizes we are using for images, margin and other element sizes. Below you can see the default Metrics file.

// @flow

import {Dimensions, Platform} from 'react-native'

const { width, height } = Dimensions.get('window')

// Used via Metrics.baseMargin
const metrics = {
  marginHorizontal: 10,
  marginVertical: 10,
  section: 25,
  baseMargin: 10,
  doubleBaseMargin: 20,
  smallMargin: 5,
  horizontalLineHeight: 1,
  searchBarHeight: 30,
  screenWidth: width < height ? width : height,
  screenHeight: width < height ? height : width,
  navBarHeight: (Platform.OS === 'ios') ? 64 : 54,
  buttonRadius: 4,
  icons: {
    tiny: 15,
    small: 20,
    medium: 30,
    large: 45,
    xl: 60
  },
  images: {
    small: 20,
    medium: 40,
    large: 60,
    logo: 300
  }
}

export default metrics

Images

When we studied Images in React Native, we learned the images may come either from an URI or locally. The interesting thing here is how they have structured this. Let's grab one piece of code from our PresentationScreen:

<View style={styles.centered}>
            <Image source={Images.clearLogo} style={styles.logo} />
          </View>

You might think: How can they do that? It's very simple. They are just wrapping the require to the image.

Look at the Images file:

// @flow

// leave off @2x/@3x
const images = {
  logo: require('../Images/ir.png'),
  clearLogo: require('../Images/top_logo.png'),
  ignite: require('../Images/ignite_logo.png'),
  tileBg: require('../Images/tile_bg.png'),
  background: require('../Images/BG.png')
}

export default images

Isn’t that awesome?

In short

We are testing Ignite and we will spend a few episodes going into more detail. So far, it’s definitely worth playing with! It has awesome concepts very well-integrated and ready for you! The framework is great for beginner and senior developers who want to use React Native in an easy and professional way.

In future episodes, we will explore more of Ignite together.

Resources