Firebase + React Native (Building an inventory App)

If you don’t want to read this and just want to view the code then it can be found here. This walk-thru assumes you know the basics of firebase.


Setup

  1. If you haven’t already you want to follow the instructions here to download npm.
  2. Go here to get the react-native cli for your given platform
  3. In your project space of choice (I typically use my desktop) run react-native init <Project Name>
  4. Once your app is created cd into that new project folder and then run react-native run-ios or react-native run-android
  5. Make sure you see the default react native screen with instructions on how to refresh the app

Let’s get coding

Open up your new project in your Text Editor of choice (I use VS Code) and take a look at the file structure. Setup your new firebase project and copy the info for a new web app (or copy my stuff). Open your App.js to look like this:

import * as firebase from 'firebase';
const config = {
   apiKey: "AIzaSyCwE3hbbjog48VhhSYdCyxKF0lJA3vA3Xg",
   authDomain: "inventoryapp-f69f2.firebaseapp.com",
   databaseURL: "https://inventoryapp-f69f2.firebaseio.com",
   projectId: "inventoryapp-f69f2",
   storageBucket: "",
};
firebase.initializeApp(config);
var database = firebase.database();
export default class App extends Component {
...
}

Finally run npm install firebase so we can make sure that our firebase import doesn’t throw errors. Now that we have added Firebase to our app lets create a new folder in your project called Components and within that folder create 3 files Header.js, ListItem.js, and Button.js. Header.js give us the nice little title bar at the top of our screen. ListItem.js helps us setup what each row of our list view will look like. Button.js will help us create a custom button for our app.

Header.js:

import React, {Component} from 'react';
import { View, Text } from 'react-native';
class Header extends Component {
   render() {
      return (
         <View>
         <View style={styles.header}/>
         <View style={styles.navbar}>
            <Text style={styles.navbarTitle}>{this.props.title}
            </Text>
         </View>
         </View>
      );
   }
};
const styles = {
   navbar: {
      alignItems: 'center',
      backgroundColor: '#fff',
      borderBottomColor: '#eee',
      borderColor: 'transparent',
      borderWidth: 1,
      justifyContent: 'center',
      height: 44,
      flexDirection: 'row'
   },
   navbarTitle: {
      color: '#444',
      fontSize: 16,
      fontWeight: "500"
   },
   header: {
      backgroundColor: '#fff',
      height: 22,
   }
};
export default Header;

ListItem.js:

import React, {Component} from 'react';
import { View, TouchableHighlight, Text, Image, Button } from 'react-native';
class ListItem extends Component {
   render() {
      return (
<TouchableHighlight onPress={this.props.onPress} onLongPress={this.props.onLongPress}>
<View style={styles.li}>
<Text style={styles.liTitle}>{this.props.item.title}</Text>
</View>
</TouchableHighlight>
);
}
};
const styles = {
li: {
backgroundColor: '#fff',
borderBottomColor: '#eee',
borderColor: 'transparent',
borderWidth: 1,
paddingLeft: 16,
paddingTop: 14,
paddingBottom: 16
},
liTitle: {
color: '#333',
fontSize: 16
},
};
export default ListItem;

Button.js:

import React, {Component} from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
class Button extends Component {
render() {
return (
<View style={styles.action}>
<TouchableHighlight onPress={this.props.onPress}>
<Text style={styles.actionText}>{this.props.title}</Text>
</TouchableHighlight>
</View>
);
};
};
const styles = {
actionText: {
color: '#fff',
fontSize: 16,
textAlign: 'center',
},
action: {
backgroundColor: '#24CE84',
borderColor: 'transparent',
borderWidth: 1,
paddingLeft: 16,
paddingTop: 14,
paddingBottom: 16,
},
};
export default Button;

Now we can work on putting everything together. So let’s return to App.js and do some code and checks.


Let’s add in our components and everything but we aren’t going to have any items in our list nor. We just want to make sure everything has the look we want.

import React, {Component} from 'react';
import {View, ListView, Alert, AlertIOS} from 'react-native';
import Header from './components/Header'
import ListItem from './components/ListItem';
import Button from './components/Button';
import * as firebase from 'firebase';
const config = {
   apiKey: "AIzaSyCwE3hbbjog48VhhSYdCyxKF0lJA3vA3Xg",
   authDomain: "inventoryapp-f69f2.firebaseapp.com",
   databaseURL: "https://inventoryapp-f69f2.firebaseio.com",
   projectId: "inventoryapp-f69f2",
   storageBucket: "",
};
firebase.initializeApp(config);
var database = firebase.database();
export default class App extends Component {
   /*Setup and state*/
   constructor(props) {
      super(props);
      this.state = {
         dataSource: new ListView.DataSource({
            rowHasChanged: (row1, row2) => row1 !== row2
      })
   };
   this.itemsRef = database.ref('inventorySimple');
   }
   componentDidMount(){
      this.listenForItem(this.itemsRef);
   }
   componentDidUnMount(){
      this.state.itemsRef.off('value');
   }
   render() {
      return (
         <View style={styles.container}>
         <Header title="Inventory Simple"/>
         <ListView
         dataSource={this.state.dataSource}
         renderRow={this.renderItem.bind(this)}
         enableEmptySections={true}
         style={styles.listview}/>
         <Button title="Add Item" onPress={this.addItem.bind(this)} />
         </View>
      )
   }
   renderItem(item) {
      const onPress = () => {};
      const onLongPress = () => {};
      return(
         <ListItem item={item} onPress={onPress} onLongPress={onLongPress}/>
      );
   }
   listenForItem(itemsRef){}
   addItem() {}
}
const styles = {
   container: {
      backgroundColor: '#f2f2f2',
      flex: 1,
   },
   listview: {
      flex:1
   }
};

P.S.: run npm install if you get an error.

Now that we know this looks pretty decent let’s update our renderItems listenForItems, and addItems method so that we can add random stuff.

...
renderItem(item) {
   const onPress = () => {
      Alert.alert(
         'Delete Item',
         'delete ' + item.title + ' ?',
         [
            {text: 'Cancel', onPress: () => console.log('cancel Pressed'), style: 'cancel'},
            {text: 'OK', onPress: () => this.itemsRef.child(item._key).remove()},
         ],
         {cancelable: false}
      )
};
const onLongPress = () => {
   AlertIOS.prompt(
      'Edit Item',
      'current item is ' + item.title,
      [
         {text: 'Cancel', onPress: () => console.log('cancel Pressed'), style: 'cancel'},
         {text: 'OK', onPress: (text) => this.itemsRef.child(item._key).update({title: text})},
      ],
   )
};
   return(
      <ListItem item={item} onPress={onPress} onLongPress={onLongPress}/>
   );
}
listenForItem(itemsRef){
   itemsRef.on('value', (snap) => {
      //get array of children
      var items = [];
      snap.forEach((child) => {
         items.push({
         title: child.val().title,
         _key: child.key
         });
      });
      this.setState({
         dataSource: this.state.dataSource.cloneWithRows(items)
      });
   });
}
addItem() {
   AlertIOS.prompt(
      'Add Item',
      null,
      [
         {text: 'Cancel', onPress: () => console.log('cancel Pressed'), style: 'cancel'},
         {text: 'OK', onPress: (text) => this.itemsRef.push({ title: text})},
      ],
   )
}
...

And that’s it! Congrats on getting your app to work. You can use this as a template and then make some even cooler stuff.


P.S. If you want a more “robust” app using navigator and everything check out this repo.

First published on Medium