April 9, 2016 - No Comments!

Quick Job Board with React Native

Part three of my “quick job board” series, this time for React Native — and deployable on mobile devices. This follows on from “quick job board in 48 lines of code” with Meteor, and the “quick job board with meteor and React” version.

The beautiful thing about React is the syntax and structure is very similar, regardless of platform — so the React Native for devices code is very similar to any web based version.

For this app we have 2 files: Index and Results. The app is only a single feed on one page, but I have broken the App into two components to keep the “pages” in separate files (as well as being better practice).

So, after installing React Native on your Mac and creating a blank app, Let’s create the index file:

index.ios.js

‘use strict’;
import React, {
 AppRegistry,
 Component,
 StyleSheet
} from ‘react-native’;

First we import the modules of React Native that we are going to use (above). Then we will "import" our Results page (below). The Results page we will create later.

var Results = require('./Results');

The index page is used simply as a navigation stack container. Our app only has one page, so this is fairly simple. We use React and NavigatorIOS as our "router": we give the page a title and set the contents (component) as our Results page (the one we imported above).

class jblyrn extends Component {
 render() {
  return (
   <React.NavigatorIOS
     style={styles.container}
     initialRoute={{
      title: 'Github',
      component: Results,
     }}/>
  );
 }
}

Now two small things are left on our Index page. We add a small amount of style to the page, to use Flexbox mainly, and we register our React app to the App Registry so that  xCode can compile it.

var styles = React.StyleSheet.create({
 container: {
 flex: 1
 }
});
AppRegistry.registerComponent('jblyrn', () => jblyrn);

Easy, no? Now let's build our job results page. Create a file called Results.js.  This is little more complex.

Results.js

First, we need access to the React components that we need, the same as we called above except we need a few extra modules this time:

'use strict';
import React, {
 AppRegistry,
 Component,
 StyleSheet,
 Text,
 View,
 ListView,
 TouchableHighlight,
 LinkingIOS
} from 'react-native';

We will use the Github jobs board again as our supplier. For now we will just set the URL to be fetched by our code later.

var REQUEST_URL = "https://jobs.github.com/positions.json";

Now we start to write our component. First the class and constructor:

class Results extends Component {
 constructor(props) {
  super(props);
  this.state = {
   dataSource: new ListView.DataSource({
   rowHasChanged: (row1, row2) => row1 !== row2
   }),
  loaded: false,
 };
}

With the contructor we are setting the initial state of the component, i.e. that the data hasn't yet loaded, for example. And we also set the datasource and type, which we will fill with data later.

Now we fetch our data. This could be written in one module, but I like to keep things separate.

componentDidMount() {
 this.fetchData();
 }
fetchData() {
 fetch(REQUEST_URL)
  .then((response) => response.json())
  .then((responseData) => {
  console.log(responseData)
  this.setState({
   dataSource: this.state.dataSource.cloneWithRows(responseData),
   loaded: true,
  });
 })
 .done();
}

The first method calls fetchData when the component has mounted, this is important. The fetchData() method then will use fetch API (More info here about this). All it does is call the Github API url we set above, parses the JSON response and places it in the dataSource variables we set in the Constructor, which will automagically create our Listview of jobs using the iOS Listview component. Magic! We also set the loaded state to true, because now we do have our data.

So, in order to let users know we are actually loading data, and the app hasn't crashed, we use a small method which shows a loading icon while the data is being fetched, and is triggered by our constructor "loaded" variable. For now just define these "renderings", which are called in turn in the main React.render method at the end.

renderLoadingView() {
 return (
  <View style={styles.container}>
   <Text>
    Loading Jobs...
   </Text>
  </View>
 );
}

Now we must also prepare the View template for each Job listing that is returned from Github, and will be placed in our Listview:

renderJobs(job) {
 return (
  <TouchableHighlight onPress={() => { LinkingIOS.openURL(job.url); }}>
   <View style={styles.container}>
    <Text style={styles.title}>
     {job.title}
    </Text>
    <Text style={styles.location}>
     {job.company} - {job.location}
    </Text>
   </View>
  </TouchableHighlight>
 );
}

This method makes use of various React components that will translate into Native ones. You can look up these React components with the Native link I pasted earlier, but briefly: Touchable highlight is a link, the web equivalent of the <a> tag; the View tag is the equivalent of the web <div> (a container) and Text might roughly translate to <span>, I guess - We can't say the coding world doesn't keep us on our toes!

The elements in curly braces are references to our styles component that applies the "css" to the view: eg. styles.container will refer to the styles object we define at the end. React uses objects to hold styling data. And the second type of data in our curly braces are the job list results: eg. job.title. Job is the object Github return to us. You can see what Github returns to us from their page here

Now we can pull the awaiting render methods together in the main method: When the data has loaded we call the ListView component (otherwise we show the "loading" component) and we pass to it the datasource, the Jobs View object we created and the stylings as "props", thusly:

render() 
 if(!this.state.loaded) {
  return this.renderLoadingView();
 }
 return (
  <ListView
   dataSource={this.state.dataSource}
   renderRow={this.renderJobs}
   style={styles.listView}
  />
 );
}

After that all that is left is to apply the styles, and export the Results component so that the Index page can reference it.

const styles = StyleSheet.create({
 container: {
 flex: 1,
 justifyContent: 'center',
 alignItems: 'center',
 backgroundColor: '#F5FCFF',
 paddingBottom: 30,
 paddingTop: 30,
 borderBottomWidth: 1,
 borderBottomColor: '#eee',
 borderStyle: 'solid'
 },
 title: {
 fontSize: 20,
 textAlign: 'center',
 margin: 10,
 },
 location: {
 textAlign: 'center',
 color: '#999'
 },
 listView: {
 paddingTop: 20,
 backgroundColor: '#F5FCFF',
 },
});
module.exports = Results;

You will need to compile this in xCode and run. You can even run it on your own device if you have an Apple developer account and watch the magic.

As before if you really have any problems, you can ping me - or - you can pull my repo. Sharing code is caring, er.. code.

Onwards, to React Desktop...

Published by: admin in Development

Leave a Reply