Posts

,

Build a Coffee Finder App with React Native and the Yelp API

Ever wanted to build an iOS or Android app? But maybe you don’t want to learn Swift or use an HTML5 wrapper? Wouldn’t it be great if you could build fast native mobile apps in the same language you write web apps in (JavaScript)? Well your prayers have been answered, with React Native, thanks to the wonderful web wizards over at Facebook.

Today we’re going to be building a coffee finder app called WheresMyCoffee. It will be an iOS app that uses the Yelp API to find nearby coffee places (perfect for coffee addicts, which is nearly everyone!).

This tutorial is won’t be super advanced but it won’t stop to define the basics of React. This is a good intro tutorial for newbies to React.

Explore React Courses

This is what your finished app will look like:

screen-shot-2016-11-04-at-3-04-04-pmscreen-shot-2016-11-04-at-3-04-12-pm

You can find the source code for this project here: https://github.com/stefanlenoach/WheresMyCoffee

The following is an outline of how we’re going to tackle this:

  1. Setup: Self-explanatory
  2. Hello World: Getting your first React Native app up and running
  3. Fetching the Data: Using the Yelp API to fetch the data we want
  4. Navigator: Setting up the React Navigator so we can access new views
  5. Displaying our Data: Pulling it all together and finishing the app
  6. Bonus: Moving forward

Part 1: Setup

  • If you don’t already have Xcode, download it from the App Store
  • Next, we’re going install Node.js and Watchman with Homebrew. Enter the following commands in an open terminal session:
brew install node
brew install watchman

Watchman is a tool by Facebook for watching changes in the filesystem. It is highly recommended you install it for better performance

  • Once you have Node and Watchman installed, we can install React Native with npm:
sudo npm install -g react-native-cli

Congratulations, you successfully installed React Native! Let’s test it out with a simple Hello World app.

Part 2: Hello World

We’ll use the React Native command line tools to create our app.

Navigate to your desktop and run the following commands in a new terminal:

react-native init WhereMyCoffeeAt
cd WhereMyCoffeeAt
react-native run-ios

If everything worked you should have a couple of new screens pop up. The first is the React Packager, which basically functions like webpack. *Leave this up in the background while you’re working on your app. The second screen should be the iOS Simulator. It might take a moment to load, but you should end up with a screen looking something like this:

Now, open up the project in your favorite text editor and pull up index.ios.js. Let’s break down what’s going on here.

import React, { Component } from 'react';

import { AppRegistry } from 'react-native'

import AppNavigator from './app/navigation/AppNavigator'

class WheresMyCoffee extends Component {

 render() {

   return (

         <AppNavigator

           initialRoute={{ident: "Search"}} />

   )

 }

}

AppRegistry.registerComponent('WheresMyCoffee', () => WheresMyCoffee)

At the top of the file we import React and a bunch of React Native components. Below that, we see the root component of our application. Anyone familiar with React will immediately understand what’s going on here. React Native components are written in .jsx and have the same lifecycle normal React components use. But you may be wondering, what are these weird <View> and <Text> tags? And where are my divs? In React Native you won’t have access to the HTML tags you’re used to. Instead, we have to import components from the React Native library. For now, just know that <View> tags take the place of <div> tags and <Text> tags replace <span> or <p> tags. You can read more on this in the Facebook docs.

Underneath our component, we see a StyleSheet object containing all our styling information. This is another idiosyncrasy of React Native, we define all our styling inline instead of abstracting it out to .css files.

Change the background color to ‘#eee’, save, and in your iOS Simulator hit Command⌘ + R. The reload times are impressive for mobile app building. Now, delete all the <Text> tags and a new one with the title of our app. Your render function should look like this:

  render() {

    return (

      <View style={styles.container}>

        <Text style={styles.welcome}>

          WheresMyCoffee

        </Text>

      </View>

    );

  }

As you can see, we define the style of an element via the ‘style’ attribute. In our case, we pass in our styles object which is defined right under our render function. Equivalently, we could define the style attribute directly like this:

<Text style={{fontSize: 30, textAlign:'center'}}>

In the next section, we’re going to build ourselves a button that retrieves data from Yelp’s API.

Part 3: Fetching The Data

We want to be able to click a button on our home screen and have it fetch nearby cafes. How do we do this? The first thing we’ll need is our location in terms of latitude and longitude. Luckily for us, we can use JavaScript’s Navigator object to do this relatively painlessly. Let’s define our state and componentDidMount functions so that our app automatically gets this data when it loads the home screen. Our state will simply define our position as ‘unknown’ to start with:

  state = {

    position: 'unknown'

  };

Now, in componentDidMount, we can use navigator.geolocation.getCurrentPosition to get our position in terms of latitude and longitude, then set our state: 

  componentDidMount() {

    navigator.geolocation.getCurrentPosition(

      (position) => {

        this.setState({position});

      },

      (error) => alert(error),

      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}

    );

  }

Great! So now our ‘position’ state should hold an object with our current latitude and longitude. How can we check this to make sure? If you click on the iOS simulator and hit Command⌘ + D, you’ll see the developer menu pop up. Click on ‘Debug JS Remotely’. A new window should open in your browser with the JavaScript console open. Now, you can add debuggers and std.out messages to your app the same way you would if you were developing for the web. Insert a debugger at the end of componentDidMount and make sure that your state is what you expect it to be.

Now, we want to use our latitude and longitude in our Yelp API request to find local cafes. Let’s create a button that will do this when we press it. First, add TouchableOpacity to your list of imports from ‘react-native’:

import {StyleSheet, Text, View, TouchableOpacity} from ‘react-native’;

This is the component we’re going to use to build our button. Next, we’ll add this to our view container and set the onPress attribute to call ‘fetchData’, our function that will make our API request. The onPress attribute is essentially the React Native analogue to onClick. Your render function should look something like this:

  render() {

    return (

      <View style={styles.container}>

        <Text style={styles.welcome}>

          WheresMyCoffee

        </Text>

        <TouchableOpacity

          style={{borderRadius: 7,padding: 10,  backgroundColor: 'rgb(37, 160, 205)'}}

          onPress={this.fetchData.bind(this)}>

          <Text style={{fontSize: 15}}>Find Coffee!</Text>

        </TouchableOpacity>

      </View>

    );

  }

As you can see, I’ve added .bind(this) to our fetchData method so that we’ll have access to the component state. I’ve also added another Text wrapper and some styling so that our button looks decent and gives the user a call to action. Now, define the fetchData method in your component and leave it empty. Reload your app and make sure everything is working properly.

We’re finally ready to start working with the Yelp API. The first thing you’ll need to do is set up a Yelp account and create a new app from the developers page

Explore React Courses

Once you create your app, Yelp will provide you with a Consumer Key, Consumer Secret, Token, and Token Secret. Now go back to your terminal and install and save OAuthSimple:

npm install –save oauthsimple

OAuthSimple will help us easily build our fetch call which we can then use to grab the data we want.  Import OAuthSimple at the top of your file:

import OAuthSimple from 'oauthsimple'

You will have to define the consumerKey, consumerSecret, token, and tokenSecret somewhere safe in your environment. DO NOT post these keys publicly. Your OAuthSimple implementation should look something like this:

      var lat = this.state.position.coords.latitude

      var lng = this.state.position.coords.longitude

      var latlng = "ll=" + String(lat) + "," + String(lng)

      var oauth = new OAuthSimple(consumerKey, tokenSecret)

      var request = oauth.sign({

        action: "GET",

        path: "https://api.yelp.com/v2/search",

        parameters: "term=coffee&" + latlng,

        signatures: {api_key: consumerKey, shared_secret: consumerSecret, access_token: token,

 access_secret: tokenSecret},

      })

Using oauth.sign creates an object with the signed URL already inside. All we have to do now is make a ‘GET’ request to this address:

      fetch(request.signed_url, {method: "GET"}).then(function(response){

            return response.json()

      }).then(function(data){

debugger

      }).catch(function(error){

        console.log("Error:", error)

      })

Reload your app and look in your developer console. If everything worked, you should be able to examine the ‘data’ object and see it has all the information we need inside of the ‘businesses’ attribute. Not too bad, right? So now that we have our data, all that’s left for us to do is present it in a way that makes sense. In the next section, we’ll restructure our program around React Native’s Navigator so we can present the user with a new screen showing our results after they press our button.

Part 4: Navigator

React Native’s Navigator handles the transition to different scenes/screens in your application. You can think of it kind of like the React Router of mobile app development. We’re going to structure our app to revolve around the navigator so we can effortlessly move to new scenes whenever we want. First, lets create a new folder in our main directory called ‘app’. This will contain our app components and navigator which we will access from index.ios.js. Inside of your ‘app’ directory create two more folders: ‘components’ and ‘navigator’.

Let’s first create a new file in our ‘components’ folder, call it ‘Search.js’, and move everything we’ve written so far into it. Delete everything related to the AppRegistry, change the component name from WheresMyCoffee to Search, and lastly export the component at the end of the file. Here’s what search.js will look like:

import React, { Component } from 'react';

import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';

import OAuthSimple from 'oauthsimple'

class Search extends Component {

  state = {

    position: 'unknown'

  };

  componentDidMount() {

    navigator.geolocation.getCurrentPosition(

      (position) => {

        this.setState({position});

      },

      (error) => alert(error),

      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}

    );

  }

  fetchData() {

    var lat = this.state.position.coords.latitude

    var lng = this.state.position.coords.longitude

    var latlng = "ll=" + String(lat) + "," + String(lng)

    var consumerKey = "***"

    var consumerSecret = "***"

    var tokenSecret = "***"

    var token = "***"

    oauth = new OAuthSimple(consumerKey, tokenSecret)

    request = oauth.sign({

      action: "GET",

      path: "https://api.yelp.com/v2/search",

      parameters: "term=coffee&" + latlng,

      signatures: {api_key: consumerKey, shared_secret: consumerSecret, access_token: token, access_secret: tokenSecret},

    })

    var nav = this.props.navigator

    fetch(request.signed_url, {method: "GET"}).then(function(response){

      return response.json()

    }).then(function(data){

      nav.push({

        ident: "Results",

        data: data

      })

    }).catch(function(error){

      console.log("Error:", error)

    })

  }

  render() {

    return (

      <View style={styles.container}>

        <Text style={styles.welcome}>

          WheresMyCoffee

        </Text>

        <TouchableOpacity

          style={{borderRadius: 7,padding: 10,  backgroundColor: '#4d9be3'}}

          onPress={this.fetchData.bind(this)}>

          <Text style={{fontSize: 15}}>Find Coffee!</Text>

        </TouchableOpacity>

      </View>

    );

  }

}

const styles = StyleSheet.create({

  container: {

    flex: 1,

    justifyContent: 'center',

    alignItems: 'center',

    backgroundColor: '#fff',

  },

  welcome: {

    fontSize: 30,

    textAlign: 'center',

    margin: 10,

    marginBottom: 30

  }

});

module.exports = Search

Now, create a new file, ‘AppNavigator.js’ in our ‘navigator’ directory. Let’s first import everything we’ll need to build our component and define our component which we’ll aptly name ‘AppNavigator’:

import React, { Component } from 'react';

import { Navigator } from 'react-native'

import Search from '../components/Search'

class AppNavigator extends Component {

  render() {

    return (

    )

  }

}

module.exports = AppNavigator

In our render method we’ll simply return the Navigator component we imported from the React-Native library:

      <Navigator

        initialRoute={this.props.initialRoute}

        renderScene={this._renderScene}

        configureScene={(route) => Navigator.SceneConfigs.FloatFromRight } />

The initialRoute attribute, as you might have guessed, defines the first scene that the navigator will render. In this example, we will pass down our initial route as props from index.ios.js. The renderScene attribute will take a method that will act as a giant switch that will give us the ability to tell the navigator what to show the user based on the route that is passed to it. Lastly, the configureScene attribute will tell the Navigator how we want to visualize the change in scene. Let us now define renderScene:

  renderScene(route, navigator) {

    var globalNavigatorProps = { navigator }

    switch(route.ident) {

      case "Search":

        return (

          <Search

            {...globalNavigatorProps} />

        )

    }

  }

renderScene takes two arguments: the route, which will determine which scene is rendered, and the navigator, which is a reference to itself. We define the globalNavigatorProps so that we can access the navigator from any scene. Finally, we create our switch which will render different scenes depending on the route we decide to pass in. Before we reload our app, let’s rewrite our index.ios.js file so that we render our AppNavigator:

import React, { Component } from 'react';

import { AppRegistry } from 'react-native'

import AppNavigator from './app/navigation/AppNavigator'

class WheresMyCoffee extends Component {

  render() {

    return (

          <AppNavigator

            initialRoute={{ident: "Search"}} />

    )

  }

}

AppRegistry.registerComponent('WheresMyCoffee', () => WheresMyCoffee)

Reload your app and make sure that everything is working the way it was before we restructured our app. We’re almost done!

Part 5: Displaying Our Data

Create a new file in our components folder named ‘Results.js’. Back in our AppNavigator.js file, we’re going to add another case statement which we will navigate to once our data has been retrieved (don’t forget to import our Results component!):

      case "Results":

        return (

          <Result

            {...globalNavigatorProps}

            data = {route.data} />

        )

Now, find your way back to Search.js. Inside our fetchData method we want to push our Results scene onto the stack, passing in the data we retrieved as props. We have access to the navigator already since we passed it in as props earlier. Your API request will look like this now:

    var nav = this.props.navigator

    

    fetch(request.signed_url, {method: "GET"}).then(function(response){

      return response.json()

    }).then(function(data){

      nav.push({

        ident: "Results",

        data: data

      })

    }).catch(function(error){

      console.log("Error:", error)

    })

Notice that once we have our data, we push the “Results” route onto the stack with our data object. We’re finally ready to start fleshing out our Results page. 

Explore React Courses

In Results.js, let’s first flesh out the skeleton of our component: import React, { Component } from ‘react’; import { StyleSheet, Text, View, Image, ListView, Linking, TouchableOpacity} from ‘react-native’; class Results extends Component {  constructor(props) {  }  render() {    return (          );  } } const styles = StyleSheet.create({ }); module.exports = Results

We’re going to display our list of items by using React Native’s ListView component. I highly recommend going through the documentation for this one since the way lists are rendered in React Native is actually quite different than the way you would for React on web apps. Before we can use the ListView we have to set up a data source, which we’ll define in our constructor function:

  constructor(props) {

    super(props)

    var dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 != r2})

    this.state = {

      results: dataSource.cloneWithRows(props.data.businesses)

    }

  }

Our state now holds a list of business objects. Let’s go back to our render function and write out our ListView component:

  render() {

    return (

      <View style={styles.container}>

        <ListView

          style={{marginTop: 100}}

          initialListSize={10}

          dataSource={this.state.results}

          renderRow={(result) => { return this.renderResult(result) }} />

      </View>

    );

  }

The renderRow attribute will display each item in the data source. We specify how the list item will be visualized in renderResult:

  renderResult(result) {

    return (

      <TouchableOpacity style={styles.resultRow} onPress={() => Linking.openURL(result.url)}>

        <Image source={{uri: result.image_url}}

       style={{width: 80, height: 80, justifyContent: 'flex-start'}} />

       <View style={{flexDirection: 'column', justifyContent: 'center'}}>

         <Text style={{fontWeight: 'bold'}}>{`${result.name}`}</Text>

         <Text>Rating: {`${result.rating}`}</Text>

         <Text>Phone: {`${result.display_phone}`}</Text>

       </View>

      </TouchableOpacity>

    )

  }


The renderResult method takes in a list item (in our case, a coffee shop object) and we use various attributes on this item to create a list that makes sense. We display the coffee shop image, name, rating, and phone number. Pressing on any of the individual items will take you to that coffee shop’s Yelp page. With some final touches to make our results page look a bit nicer, your Results.js file should look like this:

import React, { Component } from 'react';

import { StyleSheet, Text, View, Image, ListView, Linking, TouchableOpacity} from 'react-native';

class Results extends Component {

  constructor(props) {

    super(props)

    var dataStore = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 != r2})

    this.state = {

      results: dataStore.cloneWithRows(props.data.businesses)

    }

  }

  render() {

    return (

      <View>

        <Text style= {styles.header}>Results</Text>

        <ListView

          style={{marginTop: 100}}

          initialListSize={10}

          dataSource={this.state.results}

          renderRow={(result) => { return this.renderResult(result) }} />

      </View>

    );

  }

  renderResult(result) {

    return (

      <TouchableOpacity style={styles.resultRow} onPress={() => Linking.openURL(result.url)}>

        <Image source={{uri: result.image_url}}

       style={{width: 80, height: 80, justifyContent: 'flex-start'}} />

       <View style={{flexDirection: 'column', justifyContent: 'center'}}>

         <Text style={{fontWeight: 'bold'}}>{`${result.name}`}</Text>

         <Text>Rating: {`${result.rating}`}</Text>

         <Text>Phone: {`${result.display_phone}`}</Text>

       </View>

      </TouchableOpacity>

    )

  }

}

const styles = StyleSheet.create({

  header:{

    textAlign: 'center',

    position: 'relative',

    top: 60,

    fontSize: 30

  },

  resultRow: {

    flexDirection: 'row',

    justifyContent: 'space-around',

    alignItems: 'flex-start',

    marginBottom: 20,

    padding: 5,

  }

});

module.exports = Results

Explore React Courses

Hit Command⌘ + R one more time and make sure nothing blows up. Your app should look like this:

Congratulations, we’re done! Hopefully you’ve realized by now that building iOS and Android apps is entirely accessible to anyone that knows React. If you’re stuck on any bugs, feel free to check out the source code.

Part 6: Bonus

If you want to take this app to the next level, I challenge you to try it on your own. Some modifications that could be interesting:

  • Sort search results by distance so that closest coffee shops appear first
  • Allow users to search for whatever they want instead of limiting the search term to coffee
  • Integrate the Google Maps API into the app and add markers corresponding to each search result
,

‘Find Your Park’ with ReactJS, Google Maps and the DarkSky API

This year marks the 100th anniversary of the National Park Service, an organization established by Congress for “preserving the ecological and historical integrity of the places entrusted to its management while also making them available and accessible for public use and enjoyment”. Among the centennial festivities is a call to get out to experience the National Parks and “Find Your Park.”

We thought it might be fun to help you plan a National Park visit with this React app that provides current forecast information for the National Parks.

See the Pen National Park Weather with React by Sev (@sevleonard) on CodePen.

In this post we will use the Google Maps API, the DarkSky API for weather forecasting, and the Recreation Information Database (RIDB) for National Parks info. We’ll wrap all this up in a React app to help you plan a National Parks trip. For more info on getting started with RIDB and Google Maps check out Interactive Mapping with Python, GeoJSON, and JavaScript and Advanced Google Maps with JavaScript. If you are coming to React from a background in jQuery this primer is a great way to get started.

In this post you will learn:

  • Some quick Python data wrangling to acquire, clean, and organize data from an API
  • How to create a Google Maps object in React, import markers from JSON, and update info windows
  • Using state properties to optimize forecast retrieval
  • Using axiom to load external data in React
  • Using Promises to encapsulate calls to the DarkSky API
  • Dealing with CORS issues in codepen

We’re covering a lot of ground in this post, so if you’re here for something specifc you might want to skip to that area:

Using Python to get National Park Data
Setting up Google Maps in React
Integrating the DarkSky API
Async Marker Retrieval
Forecast Promises
Getting the forecast: state or API?

Getting Information on National Parks


Using the RIDB organizations endpoint we can get a list of all properties managed by the National Park Service. We’ll use a bit of Python to get this info from the API and store it into a flat file for use by our React app later on. You will need to get a RIDB API key to execute this code.

endpoint = 'https://ridb.recreation.gov/api/v1/organizations/{orgID}/recareas'
# NPS is org_id 128
org_id = 128

offset=0
params = dict(apiKey= config.RIDB_API_KEY, offset=offset)
nps_url = endpoint.replace('{orgID}', str(org_id))
resp = requests.get(url=nps_url, params=params)
data = json.loads(resp.text)
df = json_normalize(data['RECDATA'])

The RIDB endpoint will return 50 records at a time. To see how many records there are for the NPS org, we can look at the TOTAL_RECORDS field in the response data:

max_records = data['METADATA']['RESULTS']['TOTAL_COUNT']

Max records is 590. There are 58 National Parks, so clearly we are getting a lot more information than we need. We’ll extract the National Parks after we download the entire list.

We’ll continue calling the API until we’ve reached max_records, adding the response data to a data frame to accumulate all the organizations. We will use the offset value to keep track of where we are in the list and update the API query to provide the next 50 records

#save the first 50 records before we iterate

df_nps = df

while offset < max_records: offset = offset + len(df) print("offset: " + str(offset)) df = pd.DataFrame() params = dict(apiKey = config.RIDB_API_KEY, offset = offset) try: resp = requests.get(url = nps_url, params = params) except Exception as ex: print(ex) break
if resp.status_code == 200: data = json.loads(resp.text) if data['METADATA']['RESULTS']['CURRENT_COUNT'] > 0:
df = json_normalize(data['RECDATA'])
df_nps = df_nps.append(df)
else :
print("Response: " + str(resp.status_code))

Now lets look for the National Parks among this list. Lets start out by just checking the name for “National Park”

df_np = df_nps[df_nps['RecAreaName'].apply(lambda x: x.find('National Park') > 0)]
df_np.shape
(61,18)

That certainly helped! Looks like we have a few extras above the 58 National Parks we have to weed out. Another thing to check for is latitude and longitude values, since we want to plot this data on a map. Lets see how many of these 61 areas are missing location info:

df_np[df_np['RecAreaLongitude'] == ""].RecAreaName
21 Arches National Park
38 Black Canyon Of The Gunnison National Park
18 Carlsbad Caverns National Park
47 Denali National Park & Preserve
43 Gates Of The Arctic National Park & Preserve
49 Glacier National Park
16 Guadalupe Mountains National Park
21 Haleakalā National Park
43 Katmai National Park & Preserve
9 Lassen Volcanic National Park
21 Western Arctic National Parklands
9 Congaree National Park Wilderness
48 Rocky Mountain National Park Wilderness

13 of the National Park areas are missing location info. Looking at the last three in the list, Western Arctic National Parklands, Congaree National Park Wilderness, and Rocky Mountain National Park Wilderness are not part of the 58 National Parks, so we will drop them from the list. For the other 10 we can look up the latitude/longitude and update the data frame with those missing values using pandas update:

# file we stored the missing lat/long values in after looking them up
missing_latlongs = pd.read_csv('missing_lat_longs.csv')
missing_latlongs.head()
RecAreaName RecAreaLatitude RecAreaLongitude
0 Arches National Park 38.7331 -109.5925
1 Black Canyon Of The Gunnison National Park 38.5754 -107.7416
2 Carlsbad Caverns National Park 32.1479 -104.5567
3 Denali National Park & Preserve 63.1148 -151.1926
4 Gates Of The Arctic National Park & Preserve 67.9204 -153.2753

#set the indexes for missing_latlongs and df_np to the RecAreaName. The update function uses the index to merge the data
missing_latlongs = missing_latlongs.set_index('RecAreaName')
df_np = df_np.set_index('RecAreaName')
df_np.update(missing_latlongs)

# RecAreaName has been converted to an index, recreate this field and reset the index
df_np['RecAreaName'] = df_np.index
df_np['newIndex'] = range(0,58)
df_np.set_index(df_np['newIndex'])
df_np = df_np.drop('newIndex', axis=1)

# check that we captured all 58 National Parks
df_np.shape
(58, 18)

#save to csv for later use
df_np.to_csv('np_info.csv')

Great! We now have all 58 National Parks and their lat/long data for the map. Next lets switch over to React to create the Google Maps object for displaying these parks.

Creating the Google Maps object


While we are able to use the Google Maps API with React, it doesn’t exactly let us do so in a way that is truly React-ish, you can read more about that issue here. That caveat aside, lets dive into creating a map in React.

We’ll start by creating a React Component object to encapsulate the methods, states, and properties for the map

class NpsForecastMap extends React.Component 

The Component class includes a number of lifecycle methods to handle creation, initialization, interaction, and disposal. Lets get started by defining some properties

  state = { 
    forecast:{} 
  };

  propTypes = {
    np_url: React.PropTypes.string,
    init_lat: React.PropTypes.number,
    init_lng: React.PropTypes.number
  };

Our app is going to generate the current forecast for each National Park when a user clicks on the marker. Since the DarkSky API isn’t free, we can keep track of if the forecast has been fetched already to avoid the overhead, both financially and in waiting on the API response, by maintaining a dictionary of forecast state. We’ll see later how this will be used to cache the current forecast.

The propTypes objects enables us to validate the inputs to our component. By parameterizing the input geojson file and the initial map center we can reuse this component with other datasets, for example, local state parks or a set of points you plan to visit on a road trip. The React.PropTypes validators enable us to confirm that the inputs received are of the expected type, though note that these validators will not screen for a valid geojson file or valid latitude and longitude, they simply check the type of the object passed.

Now that we have setup the component properties, lets take a look at some of the methods for our NpsForecastMap component.

The render() method is required, and will read the state and props properties of the component. This method will also contain the HTML representation of our component to be added to the DOM at the time of rendering. For the NpsForecastMap component will simply add a div for React to reference when building the map, as we will see later:

render() {
    return

}

Remember from previous articles that we need to give the map divs a defined size:

.NpsForecastMap {
height: 100%;
position: absolute;
width: 100%;
}

In the HTML we have a div available for React to render the component in:

<div id="container"></div>

At the end of our React App file, we will attach the Map component to the div “container”.

ReactDOM.render(, document.getElementById('container'));

After the NpsForecastMap component has been rendered we can initialize the Google Maps object in the ComponentDidMount method, which runs after the initial rendering has occurred:

componentDidMount() {
    this.map = this.createMap()
    ...
  }
  
createMap() {
    let mapOptions = {
      zoom: 3,
      center: this.mapCenter()
    }
    return new google.maps.Map(this.refs.mapdiv, mapOptions)
  }

mapCenter() {
    return new google.maps.LatLng(
      this.props.init_lat,
      this.props.init_lng
    )
  }

Notice that we are creating the map by referencing the mapdiv ref we created in the render() method. By providing references to entities with in the NpsForecastMap component we can avoid having to directly reference the DOM.

Async Marker Retrieval


In React apps, we want to leave the DOM rendering to React as much as possible, meaning JQuery’s methods of direct DOM manipulation don’t play nice with the React paradigm. For async calls to APIs, we can use the axios promise-based HTTP client in place of AJAX. Lets take a look at how to do that for loading the National Park geojson file.

After creating the map in the componentDidMount method, we will call a method to load the geojson and create the makers for the map.

componentDidMount() {
    this.map = this.createMap()
    this.loadFeatures()

Taking a look at the first part of the loadFeatures function, we can see how similar the axios API is to JQuery for getting data:

  loadFeatures() {
    ...
    var self = this
    axios.get(th.props.nps_source)
        .then(function(result) {   
           ...

Notice that we are saving the context ‘this’ off to a local variable ‘self’. When working with async calls its important to remember that we will be operating in a different scope when the callback occurs, so ‘this’ will pertain to that local scope, not the scope in which we called loadFeatures. Creating a variable to encapsulate the initial scope will enable us to refer to methods and properties of the class when handling the result from the async call.

When we get the result from the axios get call, we’ll iterate through each feature in the collection and create the markers:

axios.get(th.props.nps_source)
        .then(function(result) {   
           for (let val of result.data.features) {
             let marker = self.createMarker(val, self.map)

Notice that we are using the ‘self’ variable to access the createMarker method of the NpsForecastMap component and to pass the map object to createMarker.

  createMarker(val, map) {
     let pointval = new google.maps.LatLng(
       parseFloat(val['geometry']['coordinates'][1]),
       parseFloat(val['geometry']['coordinates'][0]));
     let titleText = val['properties']['title']       
     let marker = new google.maps.Marker({
       position: pointval,
       map: map,
       title: titleText
     });
    
    return marker
  }

Once we parse the geojson we can create a new Marker object with the features, using the ‘map’ parameter to link the marker to the NpsForecastMap property. Now the marker will display on the map. We’ll come back to the markers to add an InfoWindow with the park name and current weather, for now lets take a look at how to get our forecast from DarkSky

See the Pen National Park Weather with React by Sev (@sevleonard) on CodePen.

Integrating the DarkSky API

Ideally, we would separate out the call to the forecast into a separate react component, ForecastAction.js for example. This would enable us to be flexible with our forecast provider, and provide a more appropriate separation of view and control in our app. We’ve started that work by creating a function with a fairly universal interface, taking only latitude and longitude as parameters and returning the current weather:

getForecast(lat, lng) {
    ...
    let request_url="https://crossorigin.me/https://api.darksky.net/forecast/8266ff95ef9bbfccf0ea24c325818f31/"

    request_url = request_url +  lat + "," + lng 
    axios.get(request_url)
        .then(function(result) {
            let content =  result.data.daily.summary

To access the DarkSky API from codepen, we need to use crossorigin.me to avoid CORS issues when querying the forecast. To do this we prepend crossorigin.me to the DarkSky API URL. Using the axios library again we query the API for our location and extract the daily summary, which will look something like:

“Mixed precipitation throughout the week, with temperatures peaking at 55°F on Saturday.”

So we have our forecast, but we have an async call within getForecast. We want to add the daily summary text to our marker info window, which needs to happen after we have retrieved the forecast. One option would be to pass the marker info window into the getForecast function, so we could directly update the info window when we get the forecast. But then we are mixing view elements with control elements, and making the call to getForecast less generic to enable swapping in a different forecast provider. Instead, we can wrap getForecast in a Promise, preserving the separation of control from view and maintaining the generic interface of the function.

Forecast Promises


Appropriate, since a forecast is kind of like a promise about the weather, your mileage may vary as to how well weather promises are kept, however.

If you are new to Promises here is an overview of the Promise object and how it works. At a high level, we will be creating a structure within the getForecast function that will enable us to call it like the axios get function, i.e.

getForecast(lat,lng)
    .then(function(result) {
        // add forecast to info window
    })

First, we need to create a promise object, forecast_p. The forecast object needs to implement a resolve directive, for providing direction on when the async method has completed successfully, and a reject method for when things don’t turn out as we expect. In this promise, we only have a resolve directive for brevity.

 getForecast(lat, lng) {
    let forecast_p = new Promise(
      function(resolve,reject) {
        ...
         axios.get(request_url)
          .then(function(result) {
            let content =  result.data.daily.summary
            resolve(content)
         }); 
      });

After we get the forecast from DarkSky we resolve with the daily summary.

With the Promise created, we can now determine what to do after the forecast has been fetched:

forecast_p.then(
      function(result) {
        return result
      }
     )

return forecast_p

The result will be the daily forecast we passed to resolve() when creating the Promise. At this point, we return the Promise so the caller can determine when to initiate the DarkSky request.

Getting the forecast: state or API?


Now that we have a mechanism for getting the forecast, we can proceed with adding a click handler to the marker. In addition to getting the current forecast (or not, depending on the state) we will pop up an InfoWindow to display the park name and forecast summary. On click, we will close the current InfoWindow, this will avoid multiple InfoWindows being created and requiring the user to manually close them. We are also creating a local variable getWeather which will be used to determine if we can read from our forecast state property or if we need to query DarkSky.

let marker = th.createMarker(val, th.map)
marker.addListener('click', function() {
    infoWindow.close()
    let title = this.title
    let infoContent = ""
    let getWeather = false-

Now, lets check our forecast state to see if we already have the weather for this marker:

// check to see if we already have the forecast for this marker
if (title in th.state.forecast) {
    infoContent = title + "
" + th.state.forecast[title]  
}
else  {
    infoContent = title + "
Loading Current Weather..."
    getWeather = true
}

Our forecast state property is indexed by park name, which is the marker title. If we can find the park in the forecast state property we can read the forecast directly from there without having the query the API. We can create the info window content directly from here.

Otherwise, we will provide a message ‘Loading current weather’ and set our getWeather variable. Based on this, we can call into our getForecast Promise, updating the info window with the result:

if (getWeather) {
    th.getForecast(marker.position.lat(),marker.position.lng())
    .then(function(result) {
        infoWindow.setContent(title + "
" + result)
        th.state.forecast[title] = result
    })
}

Check it out for yourself! There are some debug messages you can check out in the console to verify if the weather is being read from state

See the Pen National Park Weather with React by Sev (@sevleonard) on CodePen.

Summary

Wow, we’ve covered a lot here. Pat yourself on the back and check out this React google maps module if you’d like to take a shortcut. Tom does a great job of React-ifying the Google Maps API in this npm module.

When you’re ready for more, consider these potential next steps

  • Add an option for the user to specify a date range to check the weather for. DarkSky has a nice historical API you can use to help plan trips ahead of time
  • Separate out the forecast and maps elements into different components for better MVC separation. Check out Tom’s repo to see how he handles references to the map object for the Marker component.
  • Instead of using Python, create another React component for getting and cleaning the National Parks data, which you can then pass as a property to the NpsForecastMap component.
, , ,

Mapping Colorado’s 14er Mountains: React and Redux Mega Tutorial

appendTo is based out of Colorado, a US state famous for the quantity and size of its mountains. 53 mountains over 14,000 feet (4267.2 meters) are located in Colorado’s borders. During the summer, many Colorado residents make it a mission to climb as many of these ’14ers’ as they can.

In this React and Redux tutorial, we will be creating an interactive map application of Colorado’s 14ers using React and Redux. No previous knowledge of Redux is required, but a basic understanding of React concepts such as the state and components will be very helpful.

Here’s a demo of the app that we’re going to build (for the sake of not making this React tutorial longer, we did not make this responsive yet)

Explore React Courses

react tutorial demo app final

Here’s an outline of what we will be doing in this React tutorial:

  1. Redux Concepts
  2. Setting Up the Project
    1. Installing Third-party Packages
  3. Accessing the App
  4. Building the App
    1. Actions
    2. Reducers
      1. currentSelectionsReducer
      2. searchReducer
      3. index
    3. Components
      1. Main Component
      2. VisibleMarkers Container
      3. VisibleCards Container
      4. MarkerList Component
      5. CardList Component
      6. SearchFilters Component
    4. Helpers

The final code is available on this Github repository

Redux Concepts

Many developers have found Redux harder to grasp than React. Before we build out the React components, we’re going to cover how Redux will be used in this application. Here are the 4 primary Redux concepts that this demo app will use:

  • State – The state is data that needs to be updated during the life cycle of a component. It contains information on the current state of the component. For example, if you have a switch that is toggled on, you might store something like switch_value in the state and then assign it a value of true.
  • Store – The store is a big JavaScript object that represents the state of the entire app. It is where you save, update, and retrieve the data that needs to be accessible throughout the whole app.
  • Actions – The specific actions in your app which allow you to update the store. For example, you can have a SWITCH_ON action which turns on a <Lightbulb> component.
  • Reducers – Reducers specify how the state may change, given a specific action. These accept the data provided by the action and use it to update the store.

To bring all these concepts together, let’s explain using a metaphor with real-world objects. This will be a simplified explanation of Redux.

Imagine you have a <Switch> component and a <Lightbulb> component. They’re independent of each other but they’re both used in your app. The <Lightbulb> component will not be aware of the changes in the state of the <Switch> component. They are separate and their state won’t affect each other. So even if you change the switch_value to true within your <Switch> component, the <Lightbulb> component won’t actually turn on. We need a way for these separate components to be able to draw from the same state. This is where Redux and ‘state management’ come in. Redux gives us a ‘store’ that can be accessed throughout the whole app. The Redux store is the single source of truth of the current switch_value.

We now have a store to serve our single source of state/data/truth. We need a way to update the store and update it in such a way that all the relevant components will be notified of the change. Those components can then update their own state and re-render. This is where Actions and Reducers come in. Actions are used to create a payload of information to update the store. Reducers are the part of Redux who receive this data. Reducers specify how the store will be updated based on the action type (switch_value) and the payload.

Redux provides the functionality to create the store, dispatch actions and subscribe to changes in the store. This is how the different components in the app get updated.

To better understand how Redux works, check out the following diagram:

redux diagram

In our demo app, a user can hover over a mountain card. Everything starts from a specific component. In this case, it’s a card component which displays the details of a mountain. When the user hovers over a card, we use React’s event system to listen for the mouseEnter event. When this event is triggered, an action (plain-old JavaScript object) containing the type and details of the action is dispatched. In this case, the only detail that we need to submit is the id of the card being hovered over.

component to action

This action goes to the store and the store executes the corresponding reducer based on the type that was specified in the action. The reducer’s job is to determine and return the new state of the store based on the details of the action. Here we can see that the reducer is fetching additional details based on the id and passes this new data back to the store. The store is then updated with this new data under the currently_hovered_card object.

action to store

Next, the store provides the default state and methods that allows the components to subscribe to changes in the store and dispatch actions that can be used to update it. This is made possible by the Provider component that comes with Redux. When the store is updated, we can execute a code that will allow us to update the state of the component involved. As you already know, React automatically re-renders the whole component if the state changes so updating the state updates the UI as well.

store to provider

Later on, you’ll also see that there are two kinds of components: containers (smart components) and plain components (dumb components). The provider component passes down the state to the containers, and the components handle the rendering of the UI.

provider to components

That’s the bird’s eye view of how Redux works, as we go through this tutorial, you’ll learn all about the details of how each of the piece is implemented.

Setting Up the Project

To quickly get started with setting up the project, we’ll be using Create React App. This allows us to install and setup all the tools required in creating a React project.

The first thing that you need to do is to install the package globally:

npm install -g create-react-app

Once that’s installed, you can now create a new project using the create-react-app command:

create-react-app 14ers-redux

Enter the newly created folder and start the development server:

cd 14ers-redux/
npm start

The root directory of the project contains the following files and folders:

  • node_modules – contains the project dependencies. Most of the time you won’t really need to touch this directory.
  • public – contains the files that are served by the server.
  • src – contains the source files of the project. The different components, reducers, and other React files are stored here. This is where we will be primarily working on, so anytime you see a file path, assume that this is the root directory.
  • package.json – contains information regarding the installed packages and the scripts that you can execute inside the project. Here are the one’s included by create-react-app:
"react": "^15.3.2",
"react-dom": "^15.3.2",

react is the main react library, while react-dom is the one that allows you to attach react components into the DOM.

Installing Third-party Packages

Aside from the one’s installed by create-react-app, we’re also going to need the following:

"picnic": "^6.2.4",
"react-google-maps": "^4.11.0",
"react-input-range": "^0.9.2",
"react-redux": "^4.4.5",
"redux": "^3.6.0"

picnic is used to beautify things. This is pretty much like bootstrap but more lightweight.

react-google-maps is used for rendering a Google map.

react-input-range is used for creating slider components that will be used for the filter controls.

redux is used for storing and managing state used by the whole app.

react-redux is used for easily working with Redux within a React app. Redux is a framework agnostic library for working with state. This means that it’s not something that’s exclusive to React. That’s why we need react-redux to provide the functions necessary for us to work with Redux inside the React environment.

Accessing the App

You can access the app at the following url: https://localhost:3000. By default it should show the default page:

create-react-app default page

Every time you make a change to any of the files inside the src directory, it will trigger a recompilation of the source files and a page refresh. This is nice because you can easily see your output whenever you make a change. Create-react-app also comes with ESlint and an error reporter so you can easily see the errors and warnings in your code.

Adding the Project Assets

So that you’ll have some content to work with, first create a photos folder inside the public directory, then download the Github repo of this project. Copy the contents of the public/photos directory of your download to the public/photos directory of the project.

While still inside the public directory, create a css folder and inside create a style.css file then add the following code:

body, html {
  height: 100%;
  width: 100%;
}

#root, .App {
    width: 100%;
    height: 100%;
}

.hidden {
    display: none;
}

#filters-container {
    width: 60%;
    margin: 0;
    padding: 0;
}

#search-results {
    height: 85%;
    overflow-y: scroll;
    padding: 20px;
    margin-top: 100px;
}

.query-container label {
    font-size: 15px;
}

ul.ranges li {
    list-style: none;
    padding: 0 10px;
}

ul.ranges {
    padding: 0;
    margin: 0;
}

.search-filters {
    position: absolute;
    z-index: 10;
    background-color: #f5f4f4;
    width: 60%;
    padding-top: 20px;
    border: 1px solid #dadada;
    margin: 0 2px;
}

.search-filters > div {
    padding: 0 20px;
}

.InputRange {
    margin-bottom: 50px;
}

.InputRange-labelContainer {
    font-size: 15px;
    color: #6b6b6b;
}

.label-text {
    font-size: 15px;
    margin-bottom: 12px;
    font-weight: bold;
}

.card-container {
    padding: 10px;
}

.photo {
    width: 100%;
    height: 150px;
}

.photo-container {
    text-align: center;
}

.name {
    font-weight: bold;
    font-size: 20px;
    line-height: 20px;
}

.range {
    font-size: 15px;
    color: #2d2d2d;
}

.details {
    font-size: 13px;
    color: #656262;
}

.details ul li {
    margin: 0;
    padding: 0;
}

.details-container {
    padding: 10px;
}

.details ul {
    padding-left: 20px;
}

.range-container {
    padding: 0 50px;
}

.is_hidden {
    display: none;
}

.card:hover {
    border: 2px solid orange;
}

Next, inside the project root, create a data folder and inside create a filters.js and mountains.js file. The contents for these files are available on the Github repo. Use the following links to view the contents of the files:

  • filters.js – The default data for the query and filters.
  • mountains.js – The mountains data which we will be working on.

Open the index.html file and right before the closing <head> tag, link to the CSS file that you’ve just created. While you’re at it, also change the value of the <title> tag and link to the Google Maps Script. Don’t forget to replace GOOGLE_API_KEY with your actual Google Maps API key. If you don’t have one, you can get it from Google Console.

    14ers Redux Clone%MINIFYHTMLb57d0a678426e2b44321794c906466a018%

Building the App

Navigate inside the src directory and open the index.js file. This file is responsible for rendering what you saw on the browser earlier. Delete all of its contents and add the following:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App'; //import main component

import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducer from './reducers/index';
let store = createStore(reducer);

import './index.css'; //add some css

ReactDOM.render(
  (
      
          
      
  ),
  document.getElementById('root')

Lines 1 and 2 should already make sense to you, but in case not, you need to import react every time you make use of jsx on the current file and react-dom to render it on the DOM.

On line 5, we’re importing the Provider component from Redux. This is a root-level component which allows us to attach the store on the component. This is the main thing that allows us to have access to the store throughout the entire app. This works by having it passed down to children components by means of the context. Later on, you’ll see how to access the store from a child component, and how to use it to dispatch and subscribe to actions that allows us to update the UI for certain parts of the app.

On lines 6 to 8, we’re importing the createStore method from Redux, and the reducers, to create a store.

On lines 12 to 18, we’re rendering the main component inside the div with the id of root.

Actions

The actions file (actions/index.js) serves as the repository for all the actions that can be performed throughout the app. Actions are plain JavaScript objects which describes what happened in the app. For example, in a grocery list app, you might have the following action when the user clicks on the “Add Item” button:

{
    type: 'ADD_ITEM',
    name: '2 dozen eggs'
}

When the user has put the item into their basket, we can have another action:

{
    type: 'ADD_TO_BASKET',
    id: 100 //auto-generated ID before the item was added
}

Basically anything that can happen inside your app can have its corresponding action. As you have noticed, actions always have a type property. This is a required property as it describes what a specific action is doing. This is how the Reducers know what to do when it receives a specific action.

The functions in this file will be called from the different components later on to perform updates to the store. It returns an object containing the data passed in as arguments, together with the type of action. The reducers that we will create later are the one’s who will utilize the data returned by the actions. This is why the number of functions in the actions file should be equal to the number of reducers that we will create later on.

We can easily omit this file and simply supply the type every time we dispatch an action, but we would be violating the programming principle that there should only be a single source of truth. Having all the actions in a single file would give a general idea to new project members on how the state is updated and what parameters are required to update it.

export const updateSelection = (key, position, showInfoWindow) => {
  return {
    type: 'UPDATE_SELECTION',
    key, 
    position,
    showInfoWindow
  }
}

export const updateQuery = (query, show_filters, filters) => {
  return {
    type: 'UPDATE_QUERY',
    query,
    show_filters,
    filters
  }
}

Putting all the actions in a single file would work for a small app like this, but it could easily become convoluted once you work on a fairly complex app. Remember to split up related actions into different files if your actions file is already trying to do too much.

Reducers

In Redux, Reducers are responsible for specifying how the store changes when a specific action is received. They’re the ones who utilize the data passed by the actions in order to update the store. They represent a separate state that is utilized in the entire app. All reducers are invoked with two parameters: the state and the action. Every time an action is dispatched, the object returned by the action is passed as the value for the action parameter. The value passed to the state parameter is the currently stored state. If you supply a default value to the state argument, it will only be used as the default value of the state the first time the app runs.

Every time an action is dispatched, all reducers are invoked. That is why we need to check for the action type then return the new state based on the action payload. Otherwise, it just returns the current state. Even though all the reducers are invoked, it’s important to note that only the reducer which handles that specific action will do the work.

currentSelectionsReducer

currentSelectionsReducer returns the state which stores the data for the currently hovered mountain.

let default_state = {
    key: null,
    position: null,
    showInfoWindow: false
};

export default function currentSelectionsReducer (state = default_state, action) {
    if (action.type === 'UPDATE_SELECTION') {
        return {
            key: action.key,
            position: action.position,
            showInfoWindow: action.showInfoWindow
        };
    }
    return state;
}

searchReducer

searchReducer returns the state which stores the data for the user’s query and filters. This uses the data from the data/filters.js file as its initial data.

import filters from '../data/filters';

export default function searchReducer (state = filters, action) {
    if (action.type === 'UPDATE_QUERY') {
        return {
            query: action.query,
            show_filters: action.show_filters,
            filters: action.filters
        };
    }
    return state;
}

index

To bring all the reducers together, we create an index.js file inside the reducers folder. Here we use the combineReducers() function provided by Redux to bring all the reducers together. We need to do this because we want to be able to access the current store value by using only a single object. Once we do this, the current selections data can be accessed by calling this.context.store.getState().currentSelections and the search results data can be accessed by calling this.context.store.getState().search. This can be done in any component which has access to the context. Later on, you’ll see how to specify that a component should use the context.

import { combineReducers } from 'redux';
import search from './searchReducer';
import currentSelections from './currentSelectionsReducer';

export default combineReducers({
  search,
  currentSelections
});

When creating reducers, you should always remember two things:

  1. Reducers should be pure functions. This means that they shouldn’t modify the state directly. As you have seen from the two reducers that we’ve created, they either return an entirely new object which represents the current state or returns the default state. If the state is an object, you can either use Object.assign() or return a new object altogether. If the state is an array, you want to use Array.concat() instead of Array.push() if you want to push a new item into the array. This is because Array.concat() creates a new array with the new item that you want to push, while Array.push() modifies the array that you supplied. If you want to know more about pure functions, check out this article from Eric Elliott: Master the JavaScript Interview: What is a Pure Function.
  2. Filtering and sorting items in the state is not the job of the reducer. For example, on a todo list app, you don’t want to create a reducer named filterItemsReducer which will modify the state based on the item status (active, done, or deleted) selected by the user. Because if the user selects done, the state will only have the items that are already crossed off the list. So if the user selects active after that, it’s no longer all of the items that will be filtered, it will only be the items that have a status of done, so you basically end up with an empty array. Later on, we’ll have a helper function that will do that job for us right before we render the items in the state.

Components

We now proceed with the different components of the app. In this section, you’ll learn how the data flows between the components of the app through the use of dispatching and subscribing on the store.

Main Component

Let’s start by creating the main component. You can do that by creating an App.js file and adding the following:

import React, { Component } from 'react';

import '../node_modules/picnic/releases/picnic.min.css'; //use picnic.css styles

import VisibleCards from './containers/VisibleCards';
import VisibleMarkers from './containers/VisibleMarkers';
import SearchFilters from './components/SearchFilters';

class App extends Component {

  render() {
    return (

); } } export default App;

The code above is pretty self-explanatory but I’d like to address one thing, and that is the difference between components and containers. As you can see above, we’re both rendering <VisibleMarkers> and <SearchFilters> but why is <VisibleMarkers> inside the containers directory while <SearchFilters> is inside the components directory? This is because it allows us to have a distinction between components that have their data handed out to them (components) and those that are providing data (containers). If you scour the internet, you will see people often call them Smart or Dumb components. Later on, you’ll see the difference between the two. But if you want to learn more about this, you can read this article on Presentational and Container components.

VisibleMarkers Container

Create the containers/VisibleMarkers.js file and add the following:

import { connect } from 'react-redux';
import MarkerList from '../components/MarkerList'; //component for rendering markers
import getVisibleMountains from '../helpers/getVisibleMountains';

import mountains from '../data/mountains'; //hard-coded mountains data

const mapStateToProps = (state) => {
  return {
    mountains: getVisibleMountains(
      mountains,
      state.search.query, //query entered by the user
      state.search.filters //filters selected by the user
    )
  }
}

const VisibleMarkers = connect(
  mapStateToProps
)(MarkerList);

export default VisibleMarkers;

In the code above, we’re creating a container called VisibleMarkers. As mentioned earlier, containers are components which fetch their own data. That data is supplied from the store. We are able to access the store from this file by means of the mapStateToProps() function. This function is where we return an object containing the data that we want to pass as props to the MarkerList component. In the above code, we’re returning an object containing mountains as the property. Its value is an array containing the filtered mountain list which is provided to us by the getVisibleMountains() function. This means that in the MarkerList component we will have a props called mountains. If it were a class-based component, you could access it by using this.props.mountains. If it were a functional component, you could access it using props.mountains.

But you may ask how is the state being passed to the mapStateToProps() function? Well, that’s where the connect() function provided by react-redux comes into play. Its the one responsible for passing the current state to mapStateToProps() function. Behind the scenes, the connect() function generates a wrapper component which subscribes to the store. So every time the store is updated with the relevant data, the new state is passed as an argument to the mapStateToProps() function.

VisibleCards Container

VisibleCards container (containers/VisibleCards.js) is pretty much the same as VisibleMarkers container, but this time it uses the CardList component to render the content.

import { connect } from 'react-redux';
import CardList from '../components/CardList';

import getVisibleMountains from '../helpers/getVisibleMountains';
import mountains from '../data/mountains';

const mapStateToProps = (state) => {
  return {
    mountains: getVisibleMountains(
      mountains,
      state.search.query,
      state.search.filters
    )
  }
}

const VisibleCards = connect(
  mapStateToProps
)(CardList);

export default VisibleCards;

Explore React Courses

MarkerList Component

Next is the MarkerList Component. This component is responsible for rendering the map as well as the markers for the currently displayed results.

MarkerList

Create a components/MarkerList.js file and import React and the components made available by react-google-maps:

import React, { Component } from 'react';
import { GoogleMapLoader, GoogleMap, Marker, InfoWindow } from "react-google-maps";

Create the MarkerList component and declare the default state inside the constructor:

export default class MarkerList extends Component {

  constructor(props, context) {
    super(props, context);
    this.state = {
      //center of the map
      defaultCenter: {
        lat: 39.113014,
        lng: -105.358887
      },
      windowPosition: null, //position of the info window
      showInfoWindow: false, //controls the info window is visible or not
      current_name: '' //the content of the info window (name of mountain or peak that's currently selected.)
    }
  }
}

Before the component is mounted, subscribe for changes in the store. The current state can be fetched by calling the getState() function in the store. This returns an object containing the global app state. Here’s what the object looks like by default:

{  
   "search":{  
      "query":"",
      "show_filters":false,
      "filters":{  
         "elevation_height":15000,
         "elevation_distance":5000,
         "prominence_height":5000,
         "prominence_distance":3000,
         "isolation_height":700,
         "isolation_distance":2000
      }
   },
   "currentSelections":{  
      "key":null,
      "position":null,
      "showInfoWindow":false
   }
}

currentSelections is the only one we need, so we extract it from the result of the getState() call and then use it to update the state of the component.

componentWillMount() {
  this.context.store.subscribe(() => {
    let state = this.context.store.getState().currentSelections;
    this.setState({
      windowPosition: state.position, //position of the currently selected mountain in the map
      showInfoWindow: state.showInfoWindow, //whether to show the info window or not
      current_name: state.key //name of the currently selected mountain
    });
  });
}

toggleInfoWindow controls the visibility of the InfoWindow. For those not aware, this is the little pop-over box which becomes visible whenever you click on a marker inside Google maps. This function gets executed when a marker on the map or the close button on the InfoWindow gets clicked. If the loc parameter is null, it means that the user has closed the InfoWindow. Otherwise, it means that the user clicked on the marker so we supply the necessary information by updating the state.

toggleInfoWindow(name, loc) {
  if (loc == null) {
    this.setState({ windowPosition: null });
    return;
  }
  let markerLoc = {
    lat: loc.latLng.lat(),
    lng: loc.latLng.lng()
  };
  this.setState({
    current_name: name,
    windowPosition: markerLoc,
    showInfoWindow: true
  });
}

In the render() function, use the <GoogleMapLoader> component to initialize Google maps. This requires a couple of props to be passed in: containerElement and googleMapElement. containerElement, just like the name suggests, requires you to pass the HTML that will serve as the container for the Google Map.

render() {
  let mountains = this.props.mountains;
  return (

} />

); }

On the other hand, googleMapElement requires the <GoogleMap> component to be passed in. It also has a couple of props: defaultZoom, which is the default zoom of the map and defaultCenter, which is the position of the center of the map.

googleMapElement={
  
  ...
  
}

Inside the <GoogleMap> component, render the markers by looping through the array of mountains. The <Marker> component accepts the position and the key as its props. There’s also an optional onClick props which is the function to call when the marker is clicked.

{mountains.map((row, key) => (
  

  

))}

Right after the loop, render an InfoWindow based on the current state. In the code below, the InfoWindow will only be rendered if showInfoWindow is true. It also accepts a position as its props. This is the same position as the markers, that is why we need to pass in an options props to adjust it accordingly. This is through the use of pixelOffset. Calling new window.google.maps.Size(0,-30) returns that position which is 30 pixels less on the Y axis. This makes it appear at the top of the marker. Note that we used window to access the Google Maps library because google is not available in the current scope.

{
  this.state.showInfoWindow &&
   { this.setState({ showInfoWindow: false }) }}
    options={{pixelOffset: new window.google.maps.Size(0,-30)}}
    >
    {this.state.current_name}
  
}

Lastly, specify the contextTypes. This tells React that we’re expecting a store object in the context. In React, the context is a set of attributes implicitly passed down from its parents to its children. In this case, the store is basically the store that we created earlier on the index.js file and was passed as a props to the <Provider> component. So when we called this.context.store.subscribe() earlier, we’re basically referring to that same store.

MarkerList.contextTypes = { store: React.PropTypes.object };

CardList Component

Next is the CardList component (components/CardList.js).

CardList Component

import React from 'react';
import Card from './Card';

const CardList = ({mountains}) => (
{mountains.map((row, key) => )}

) export default CardList;

The CardList component uses the Card component (components/Card.js) to render the mountain details. It’s also responsible for adding the event handler for when the cards are hovered over. Start by importing the files that we need. Here we’re extracting the updateSelection() method from the actions/index.js file. We didn’t need to specify /index after the folder name because it’s already assumed that we’re referring to an index file if it’s omitted. As you have seen earlier, this file houses all the actions that can be performed throughout the app.

Explore React Courses

import React, { Component } from 'react';
import { updateSelection } from '../actions';

Create the Card component and add a showInfoWindow() function. This function is executed every time the user hovers over a card. It’s responsible for dispatching the action which updates the state for user selection. This state stores the data for the currently hovered card. That’s why the function expects the general mountain details stored in the properties parameter, as well as the position (coordinates) of the marker in the map. We then use this data to dispatch the updateSelection action. In Redux, the way we dispatch an action is by calling the dispatch() method from the store. The store then invokes the reducer functions. Earlier in the reducers/index.js file, we used the combineReducers() functions to create one big object that houses all the state that we need to keep track of. This means that all reducers that we supplied to that function will get invoked. That’s why we were checking the action type on each reducer so that only the reducer which knows what to do with the action will be executed. The store passes in two arguments to the reducer: the current state and the actual action object. You can just imagine that the store executes a code similar to the following every time an action gets dispatched:

var currentState = { 
  currentSelections:{  
    key: null,
    position: null,
    showInfoWindow: false
  }
}

var action = {
  type: 'UPDATE_SELECTION',
  key: "Mount Massive",
   position":{  
      lat: 39.1875,
      lng: -106.4757
   },
   showInfoWindow: true
}

let newState = currentSelectionsReducer(currentState, action); //the new value for the corresponding state

Once the store is updated, it will notify all the subscribers that the store has been updated, which then allows them to fetch the updated data using the getState() function. We did this earlier inside the componentWillMount() function of the MarkerList component. This allowed the component to show the InfoWindow on top of the target marker.

export default class Card extends Component {
  showInfoWindow(properties, coordinates, event) {
    let position = {
      lat: coordinates[1],
      lng: coordinates[0]
    };
    let showInfoWindow = true;
    this.context.store.dispatch(
      updateSelection(properties.name, position, showInfoWindow)
    );
  }  
}

We can’t really leave the InfoWindow hanging around when the user is no longer hovering over a card, that’s why we need the hideInfoWindow() function to dispatch an action which will tell the MarkerList component to hide the InfoWindow.

hideInfoWindow() {
  let key = null;
  let position = null;
  let showInfoWindow = false;
  this.context.store.dispatch(updateSelection(key, position, showInfoWindow));
}

The render() method displays all the relevant details from the data source as well as attach the functions for showing and hiding the InfoWindow on MouseEnter and MouseLeave events.

render() {
  let photo = "/photos/" + this.props.data.photo;
  let properties = this.props.data.properties;
  let coordinates = this.props.data.geometry.coordinates;

  return (

 

 

{properties.name}

 

 

{ properties.name }

 

{ properties.range }

 

 

    • Elevation { properties.elevation[0].toLocaleString() } ft, { properties.elevation[1].toLocaleString() } m

 

    • Prominence { properties.prominence[0].toLocaleString() } ft, { properties.prominence[1].toLocaleString() } m

 

    • Isolation { properties.isolation[0].toLocaleString() } mi, { properties.isolation[1].toLocaleString() } km

 

 

 

 

 

); }

SearchFilters Component

We now need to implement the SearchFilters component (components/SearchFilters.js).

SearchFilters Component

This is responsible for displaying the search field and all the filters used in trimming down the search results. Inside the file, first, import the slider and its default styling. We’ll be using the react-input-range package to easily create sliders that the user can use to select the elevation, prominence and isolation of the mountain they’re looking for.

import React, { Component } from 'react';
import InputRange from 'react-input-range'; 
import '../../node_modules/react-input-range/dist/react-input-range.css'; 

Import the initial filters. This is called filters but it includes the query as well.

import filters from '../data/filters';

Extract the updateQuery() method from the actions file. This allows us to update the current user query.

import { updateQuery } from '../actions';

Create the SearchFilters component. Inside the constructor() set the initial state to that of the data contained within the data/filters.js file.

class SearchFilters extends Component {

  constructor(props, context) {
    super(props, context);
    this.state = filters;
  }
}

The updateStore() method gets executed every time the user types in something in the search field or when the sliders are adjusted. This is where we dispatch the updateQuery action which we created earlier on the actions/index.js file. As you have seen earlier, the action accepts the current value of the query text field, the checkbox for showing or hiding the filters, and the selected filters.

updateStore() {
  this.context.store.dispatch(
    updateQuery(this.state.query, this.state.show_filters, this.state.filters)
  );
}

The onQueryChange() function updates the component state with the current value inputted by the user in the search field, then calls the updateStore() function to update the store. This will trigger the mapStateToProps() function in the VisibleMarkers and VisibleCards component to be called, which in turn calls the getVisibleMountains() function to return an array containing only the mountains which match the user’s query.

onQueryChange(event) {
  this.setState({
    query: event.target.value.toLowerCase()
  }, () => {
    this.updateStore();
  });
}

toggleFilters() simply flips the current value for the show_filters in the state. This controls whether the filters are hidden or shown.

toggleFilters(event) {
  var show_filters = !this.state.show_filters;
  this.setState({
    show_filters
  });
}

updateFilter() is basically doing the same thing as the onQueryChange() function. But this time, it updates the value for the filters instead of the query.

updateFilter(id, component, value) {
  let current_filters = this.state.filters;
  current_filters[id] = value;

  this.setState({
    filters: current_filters
  }, () => {
    this.updateStore();
  });
}

Render the text field for entering the query as well as the different filters. The sliders requires the following props to be passed in:

  • maxValue – the maximum value allowed by the slider.
  • minValue – the minimum value allowed by the slider.
  • value – the current slider value.
  • labelSuffix – the text to display right after the max, min and current value.
  • onChange – the function to execute when the slider value changes.
render() {
  return (

 

 

 

); }

Since we’re using the store passed through the context, we need to specify the contextTypes again:

SearchFilters.contextTypes = { store: React.PropTypes.object };
export default SearchFilters;

Helpers

Helpers are functions that are used in multiple files throughout the app. These functions are usually used to filter data based on specific parameters. In our case, we’re using it to filter the mountains data based on the query and filters selected by the user. You would normally have this function inside a container component. But since we have two containers which needs this function, we took it out to a separate file and just have it imported. The file path is helpers/getVisibleMountains.js.

const getVisibleMountains = (mountains, query, filters) => {

  let filtered_mountains = mountains.filter((mt) => {
    let name = mt.properties.name.toLowerCase();
    let range = mt.properties.range.toLowerCase();
    if(((query !== '' && name.indexOf(query) !== -1) || (range.indexOf(query) !== -1))
      && (filters.elevation_height >= mt.properties.elevation[0]
        && filters.elevation_distance >= mt.properties.elevation[1]
        && filters.prominence_height >= mt.properties.prominence[0]
        && filters.prominence_distance >= mt.properties.prominence[1]
        && filters.isolation_height >= mt.properties.isolation[0]
        && filters.isolation_distance >= mt.properties.isolation[1]
        )) {
      return mt;
    }
    return false;
  });

  return filtered_mountains;

}

export default getVisibleMountains;

Explore React Courses

Review

To really drive home the point of using Redux, let’s run through how the app works one more time.

The app is made up of four main components:

  • Card
  • CardList
  • MarkerList
  • SearchFilter

One of the main principles of React is to have a number of components that can be reused throughout the whole app. Which is why each of the components should be able to work independently, except for parent-child components such as the CardList and Card. But this also means that we cannot have the components talk to each other, because if we do so, we will be creating a dependency between each of them. For example, the MarkerList and CardList components are essentially presenting the same data, only in a different form. So the original problem was how to create a link between these two components. This is where we used Redux to solve the problem. With Redux we were able to create a store that can be used by the whole app. We then updated this store by using actions and reducers. Actions describe what specific arguments are required to update the store while reducers are the one’s that describes how the store will change based on the data passed by the actions. Whatever value the reducers return will become the new value of that specific state in the store. By using these two, we were able to dispatch and subscribe to actions from any component in the app with the help of react-redux. We used the Provider component provided by react-redux as the root component for our app. This component allowed us to link the store to our React app. From there we just used React’s context to get a reference to the dispatch() and subscribe() functions from the store. For example, we used the dispatch() function on the SearchFilter component every time a change is made to the query or any of the filters. We then used the connect() function to automatically subscribe to the changes made to the store from the VisibleCards and VisibleMarkers container. This allowed us to re-render the CardList and MarkerList components every time the store is updated. This is made possible by the mapStateToProps() function in which the new store value is getting passed every time it’s updated. From there, we then returned only the mountains that matches the user’s query. The data that we returned are then passed as props to the CardList and MarkerList components which is finally presented to the user.

Conclusion

In this React and Redux tutorial, you’ve created an interactive 14ers clone. By doing so, you learned how to use Redux for managing application state within a React environment. You also learned concepts like the store, actions, reducers, dispatch and subscribe for making data flow throughout the whole application.

Further Reading

, , ,

Carved In Stone: Immutables in JavaScript

Immutability – the idea that you should never work with “live” data, is slowly transforming the way that programmers work with objects, data and streams. From reducing hidden variables in functions to making database programming simpler to reducing the chance for difficult to find bugs to make its way into your code, immutability is becoming the quiet revolution in Javascript.

This particular piece is going to dig into what immutability actually means in programming (specifically in JavaScript, and even more specifically the React library). There’s more than a bit of theory here, but the goal is to illustrate why immutability – as a design pattern and a library – can make such a big difference in code.

Javascript’s Reference Problem

When most neophyte programmers are learning about functions, at some point they discover that objects can be passed as parameters. It’s perhaps at this point that the true nature of objects begin to manifest. An object can be passed by value, in which case, when you supply the object, the system creates a duplicate of that object, or it can be passed by reference.  Passing by reference means that if you change the object within the function, you are actually modifying the original object, not a duplicate.

Javascript in general dispenses with passing by value for anything except for pre-existing data types such as strings – everything is passed by reference. This can have some interesting consequences. For instance, suppose that you have an array of colors within a variable, then use the invoke a function to an item to that list at the end.

function addItem(array,value){

array[array.length]=value;

return array;

};

var colors = ["red", "green", "blue", "orange","yellow","aqua"];

var extColors = addItem(colors,"black");

The problem with this is that if you look at both variables afterwards, you’ll discover that they contain the same list:

console.log(colors,extColors)

// colors: ["red", "green", "blue", "orange", "yellow", "aqua", "black"]

// extColors: ["red", "green", "blue", "orange", "yellow", "aqua", "black"]

More experienced programmers understand that, because the colors array was passed (implicitly) by reference, the original array was modified and then passed back. Indeed, in order for the function to pass back a distinct array, it’s necessary to create a copy of the existing array then modify that:

function addItem2(array,value){

var newArray = new Array[array];

newArray[newArray.length]=value;

return newArray;

};

This will create the expected result:

var colors = ["red", "green", "blue", "orange","yellow","aqua"];

var extColors = addItem2(colors,"black");

console.log(colors,extendedColors)

// colors: ["red", "green", "blue", "orange", "yellow", "aqua"]

// extColors: ["red", "green", "blue", "orange", "yellow", "aqua", "black"]

The advantage to working by reference is that it avoids the allocation of a new object. However, there are some significant disadvantages to it, disadvantages that become more evident the more complex a project becomes. One of the biggest is that when you pass objects by reference into a function, you do not necessarily know what that function is going to do with your data. It could add additional data, remove data, rearrange information, perhaps even assign something altogether different. It’s like taking in a cat to the vet to get her claws clipped, only to get a St. Bernard (with clipped claws, mind you) when you pick her up.

This problem is frequently referred to as the hidden variables (or side effects) problem, and it can prove fiendishly difficult to debug when it happens, especially in this day and age of extended frameworks. Side-effect-free programming means that nothing can be passed by reference, and the result of a function should be free of previous references.

This approach to programming has some interesting implications. First, it means that such functions are considered composable – the output of one function can be used as the input of another, and any large action can be then broken down into a sequence of smaller functions.

Indeed, computer science identifies such programming as being functional (made up of composable functions) rather than imperative (command oriented). Javascript has been heavily influenced in the last year by concepts from functional languages such as Lisp, Scheme, Haskell, Miranda, and OCaml, as well as more recent languages such as Clojure and F#. Indeed, many of the more widely used EcmaScript 6 features, such as arrow functions, and destructuring, come directly from languages such as Haskell.

Immutables and Passing By Value

Because Javascript doesn’t have a “pass by value” parameter mode for objects, it’s necessary to circumvent the natural behavior of Javascript. To make this happen a number of libraries have sprung up around the notion of immutability, with the dominant one (and the one covered here) being immutable.js produced by the Facebook team.

Immutability implies changelessness (“mutate”, of course, means “to change”). A variable that is completely immutable, however, is pretty useless, as you couldn’t assign a value to it in the first place. Here, the distinction is that, once you have assigned a certain object value to that variable, you cannot remove information … you can only add to it. What’s more, what gets returned is a distinct object.

For instance (assuming you’ve added the appropriate library), the immutable List object gives you similar functionality to the Array object:

var list = Immutable.List(["red","green","blue"])

console.log(list);

// List [ "red", "green", "blue" ]

var list2 = list.push("yellow");

console.log(list2);

// List [ "red", "green", "blue", "yellow" ]

var popped = list.last();

var list3 = list.pop()

console.log(list3 , popped);

// List [ "red", "green"], "blue"

Note that while List.push() has a similar effect to what Array.push() does (though it returns a new list), List.pop() returns a new list copying the old one, but removing the last item. This means that you need to retrieve the end of the list first (the thing being popped off) before calling the list.pop() function.

The Immutable.js library incorporates a number of related data structures – Lists, Sets, Maps, Ordered Maps, Stacks, Ranges, Sequences (Seq), Records and Iterables, along with the abstract Collection structure that underlies the others. Most of these have been optimized to provide the minimum necessary storage for the types. For instance, you can set a range (a sequence of consecutive numbers) to have an infinite number of items. These range object doesn’t actually store this (for obvious reasons), but instead provides an iterator function that produces new items with the appropriate value when needed.

It should be noted that ES6 does not have native immutables, though classes can be built that provide this functionality. Whether immutables will make it into a subsequent version of Javascript natively is still being determined.

React’s Immutables and Efficient Processing

One of the key benefits of MVC frameworks is the concept of data binding – a variable (or data in general) is bound by a user interface controller to a specific presentation view. By changing the data you change the view and vice versa. While React is not a full MVC (it only handles the view layer), internally React maintains a virtual DOM that is optimized to determine whether a given subcomponent needs to be refreshed. Put another way, React doesn’t bind user interface controls directly, but instead re-renders subcomponents when its internal model changes.

As such, immutability can play a major role in React – and in fact can vastly improve performance there. To understand why, a couple of diagrams can prove useful:

Diagram 1. React components with mutable deep source JSON.

In Diagram 1, a React component updates up to three levels deep. Each “node” is a DOM node that is created in memory, then compared to what is already there. If the calculated DOM output is the same as what’s there, that node is not updated, but any child components still must go through this same process. This means that, here, React has to look at 12 of 15 nodes, and change roughly half, avoiding the final three only because the data for generating the need is a leaf and hence either changed or unchanged for all children.

The key to making this happen is the shouldComponentUpdate() method of the React class, which returns true if the component needs to be updated and false otherwise. The React base class has it’s own sCU() function, but by writing a new one you overwrite this for those components where such comparisons take place.

React.createClass({
propTypes: {
value: React.PropTypes.string.isRequired
},

render: function() {
return <div>{this.props.value}</div>;
}

shouldComponentUpdate: function(nextProps, nextState) {
return this.props.value !== nextProps.value;
}
});

Diagram 2. React component with immutable data.

In the case where data structures are guaranteed immutable, there are two comparisons – the first is, as above, whether the pre-rendered DOM structures have changed, while the latter indicates whether the source data itself has changed. Once React has a guarantee that a deep source data structure is the same all the way down, then this can shortcut the need to check every node.

This means that, in the above case, rather than needing to check 80% of the nodes, you only need to check 45%, and only need to change 4. The can result in huge performance differences, especially for complex renders.

var someRecord = Immutable.Record({ foo: null });



var y = x.set('foo', 'baz');
x === y; // false

React.createClass({
propTypes: {
value: React.PropTypes.string.isRequired
},

render: function() {
return <div>{this.props.value}</div>;
}

shouldComponentUpdate: function(nextProps, nextState) {

return this.state !== nextProps.value;
}
});

Immutability makes this process a little more difficult in some respects, though easier in others. In a mutable framework, you need to place observers on variables in order to determine when a specific value has changed, then you have to navigate to the view to modify just that particular value. This means that you end up with a great number of dependencies, that often have an adverse impact upon performance.

With immutability, on the other hand, you do not need to know precisely what changed. This means that when you update a specific instance in your model at any point, you are changing the whole instance. By binding to the instance rather than a specific value in that instance, the component in question would then just update the visual appearance of the whole component. This can make for a slightly less granular design, but has no hidden variables, and more to the point becomes recursively composable – you only modify things that are specifically in the context of the component, not the framework that the component is in. You also have the advantage of being able to archive the old state in toto for that component, possibly associating it with a time stamp. This makes “undos” much easier.

Using React, you can add support for immutables by requiring the “react-addons-update.js” library from the React site.

The following shows how such immutables may be changed in React, with the update() function handling the process of creating a new immutable from an existing one.

App.data = obj = {a: 10, b: 7};
var newObj = update(obj, {b: {$apply: (x)=> x * x}});

save(newObj);

App.data = newObj;

App.render();

The notation {$apply: (x) => x*x} is an example of a command, and includes $apply, $set, $push, $unshift, $splice and $merge, the dominant mutation commands. More information about immutables in React can be found at https://facebook.github.io/react/docs/update.html.

An Immutable React Example: Image Viewer

One of the best ways of understanding immutables is to see a working example. The following is a React component that allows users to enter in URLS of pictures, see a preview, then add this to an image carousel of thumbnails. When you click on a thumbnail, the larger image is displayed, as shown below.

screen-shot-2016-09-20-at-11-02-29-am

JS Bin on jsbin.com

While the application is a comparatively simple one, it does illustrate one way that React makes use of immutable data structures. The code for the image viewer can be seen below:

/* This retrieves the List and Map structure from the React + Extensions library, and identifies these as being immutable objects. Note that these use the immutable.js data structures not the new Map and List ES6 core classes. This means that changing a map or list will always create a copy of that structure rather than a reference to the original structure. */

var { List, Map } = Immutable;
/* The React component in the render() method can define both inline styles (by passing javascript objects as shown here, and CSS classes (by using the className property). These largely handle the layout of the component. */
var styles = {

imgStyle:{

maxWidth:"250px",

maxHeight:"250px"

},

itemStyle:{

maxWidth:"250px",

maxHeight:"250x",

backgroundColor:"black"

},

containerStyle:{

display:"inline-block",

maxWidth:"270px",

maxHeight:"600px",

overflowY:"auto",

border:"inset 2px gray",

backgroundColor:"black"

},

timestampStyle:{

color:"white"

},

widgetStyle:{

display:"block",

verticalAlign:"top"

},

displayWidgetStyle:{

display:"inline-block",

verticalAlign:"top"

},

displayImageStyle:{

maxWidth:"800px",

maxHeight:"800px"

},

};

 

/* This is the Component class creator, used to build the <component> object */

var Component = React.createClass({

/* This sets up the default data object that holds the state for the application. Note that the Map here is an immutable object, so rather than setting the values internally, this becomes the state that then becomes copied when the application starts, and new states are created by mutating these copies and making them the working data copy within the React system. In this case, items is an (empty) immutable list, url is the working url, and index is the selected item from the list. */

getInitialState() {

return {

data: Map({ items: List(), url: "",timestamp:"",index:-1 })

}

},

/* The render is shown every time there is a mutation event upon the initial state object. This creates a comparison DOM against what React already holds, and only if the resulting pre-rendered DOM is different from the existing DOM does React render that portion.

Again it's also worth noting that render() makes use of React's HTML-like structure, which looks similar to HTML but has different conventions with regard to how output is bound to properties or the state variables initially defined in the getInitialState() method.

Also note the use of ES6/2015 style arrow statements, designed to emulate anonymous functions for callbacks. The 'data' variable echoes the current "state" as it evolves from the initial conditions.  */

render() {

var data = this.state.data;

return (

<div>

<div style={styles.widgetStyle}>

<input type="text" onChange={this.handleURLChange} value={data.get('url')}/>

<button onClick={this.handleAddItemClick}>Add Item</button>

</div>

<div>

<div style={styles.containerStyle}>

{data.get('items').map((item,index) =>

<div style={styles.itemStyle}>

<div><img src={item.url}  style={styles.imgStyle}  onClick={this.handleThumbClick} data-index={index}/></div>

<div style={styles.timestampStyle}>{item.index}: {item.timestamp}</div>

</div>

)}

</div>

<div style={styles.displayWidgetStyle}>

<img src={data.get('url')} style={styles.displayImageStyle}/>

</div>

</div>

</div>

);

},

/* The handle URLChange function updates the "working" URL of the images from the input box, and when rendered, will change the view image. Note that each of receives a specialized "super-event" object from React that can be used to get information appropriate to the event type. These are not Javascript events, though they contain the information from such events, but are used in part to pass information back to the React framework.   */

handleURLChange(evt){

var newValue = var activeIndex = evt.currentTarget.value

console.log(newValue);

this.setState(({data}) => ({

data: data.update('url',v=>newValue)

}));

},

/* When the thumbnails in the carousel are clicked, this reads the index property from the assigned data-index property and from that uses this to compute which url is used for the large image. The setState function here then updates this URL and creates a new state object, replacing the old.   */

handleThumbClick(evt){

var activeIndex = evt.currentTarget.dataset.index;

var url = this.state.data.get('items').get(activeIndex).url;

this.setState(({data}) => ({

data: data.update('url',v=>url)

}));

},

 

/* The handleAddItemClick function increments the active index by one, then creates an object consisting of the new url, index and a timestamp and puts it onto the list. Again, because of the use of immutables, these operations are more optimal for updating. The unshift function is similar to the push() function on an array, except that it places the object into the beginning of a list rather than the end. This means that the last item entered will always be at the top of the list.      */

 

handleAddItemClick() {

this.setState(({data}) => ({

data: data.update('index',v=>v+1)

}));

this.setState(({data}) => ({

data: data.update('items', list => list.unshift({

index:data.get('index'),url:data.get('url'),timestamp:(new Date()).toLocaleString()}))

}));

}

});

/* This then kicks of the process of rendering the (anonymously named) <Component element to take up the entire document. Setting it to a subordinate container element will render it just in that element, not replaceing the whole page content.   */

React.render(<Component />, document.body);

The results of this code can be seen and explored with at  https://output.jsbin.com/zonihem.

The Benefits of Immutables

Preventing corruption by ensuring that existing data can’t be overwritten is one area where immutables provide useful. There are others. One such, as a design principle, comes in separating the data of an object from its operations. This may seem more than a little counterintuitive. After all, isn’t one of the biggest benefits of object oriented programming the fact that you can in fact encapsulate (or bundle) data together with its operations?

The answer may surprise you. Object oriented programming arose at a time when most applications were stand-alone, and the number of objects in play were typically fairly small. The benefit of retaining state was also fairly small for many of these objects, so you could effectively update the state of an object by overwriting the previous state, without worrying about retaining previous information.

That began to change as applications began to span tiers. Increasingly, data structures have resided in documents, either JSON or (less commonly) XML, located on servers. In this case the Javascript acts like a function to modify the document as a unit, then update this back to the server.

This idea of treating data contextually – not just single values but essentially all of the local information about a given entity – has a profound impact on development. Most information is not atomic – you seldom change a street address without changing city, state and zipcode. In an immutable world, this entity becomes, in essence, a key part of a transaction, and the transaction is only committed once the information it contains is complete and internally consistent. As such, working on copies of things only makes sense, and functions should then be seen as things that can change the entity as a whole.

Immutables carry this concept into the core of coding, reminding you as the coder that you are working not on individual properties (or even records) but objects as a whole. As such the use of immutability prevents incomplete (or improper) transactions, enables better code pipelines and prevents unexpected side effects that can add significantly to the debugging cycle cost and time.

Kurt Cagle (kurt.cagle@gmail.com) is an author, information architect and Javascript programmer. He is available for Javascript, node, MarkLogic and semantic software development.

,

What is the difference between state vs. props in React?

React is an open-source JavaScript library that provides the V (view)  of traditional MVC JavaScript framework. React promises programmers a model in which subcomponents cannot directly affect enclosing components- meaning data is flown downwards, updating data changes in HTML efficiently, and abstracts away the DOM allowing better performance using Virtual DOM.

You may ask, if data is only flown downwards from components to components, how could we access data we need from previous component? The answer to that is props. React uses props to transfer data we need to different components.

Explore React Courses

Let’s jump into the code to show you the difference between the two. We’ll first create simple React Component to render to virtual DOM to show examples.

Code Example:https://jsfiddle.net/qtn6xphx/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

 render: function() {

   return (

     <h1>sample</h1>

   );

 }

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

We can also pass in components state data through props but we’ll go over that later. Say that we have another component and we’d like to pass a data from our SampleOneComponent. React’s prop can handle this for us.

We’ll create another component called SampleTwoComponent. Lets make simple <h2></h2> element and render it below our <h1></h1> heading from SampleOneComponent.

Code Example:https://jsfiddle.net/qtn6xphx/1/

Remember that we always need to wrap our elements within parent’s <div></div> when rendering more than one element within a component.

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

 render: function() {

   return (

    <div>

       <h1 className="sample-one"> this is sample one </h1>

       <SampleTwoComponent />

     </div>

   );

 }

});

var SampleTwoComponent = React.createClass({

render: function() {

  return (

    <h2 className="sample-two"> this is sample two </h2>

   )

 }

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

Now that we have our two components set up, let’s use React’s prop to pass a data from SampleOneComponent to SampleTwoComponent. For our example, we’ll pass along a simple string data.

By placing a reference called “sampleString” in our <SampleTwoComponent /> element in our SampleOneComponent, we’re able to pass the string “this is string from sample one component” down to our SampleTwoComponent.

Code Example:https://jsfiddle.net/qtn6xphx/2/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

render: function() {

return (

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent sampleString="this is string from sample one component"/>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<h2 className="sample-two"> this is sample two </h2>

)

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

For now we haven’t checked to see if the string data was actually transferred down, so let’s go ahead and check to see if we received our string data. The way we can access the sampleString reference is using React’s this.props. This keyword will always reference current component and props object will hold all the different props that were passed. To check our prop data, we’ll go ahead and render a <p></p> element holding the props data below our <h2>this is sample two</h2>

Code Example:https://jsfiddle.net/qtn6xphx/3/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

render: function() {

return (

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent sampleString="this is string from sample one component"/>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

</div>

)

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

As you can see, SampleTwoComponent is able to access our string data that was sent from SampleOneComponent. This is a simple example and as I have mentioned before, we can transfer any type of data through props. Before I get into React’s state, as I pointed out earlier, you can have multiple props in the component. Prop is a JavaScript object, so all you have to have is key value pairs.

Code Example:https://jsfiddle.net/qtn6xphx/5/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

render: function() {

return (

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

While developing using React, you’ll be using a lot of prop but another important feature is state. React’s state can be defined as key value pair defined in each component and can be accessed with this.state. State can be initialized when code is loaded or state can be set on event changes. Let’s go ahead and use our same example we used for props to understand state.

Explore React Courses

We can initialize component’s state on load by using getInitialState() function.

Code Example:https://jsfiddle.net/qtn6xphx/6/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "John",

lastname: "Doe",

age: 32

}

},

 

render: function() {

return (

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

This will allow us to use our state data without having to render as undefined.

Let’s do an example to show data from our state in our render function in SampleOneComponent

Code Example:https://jsfiddle.net/qtn6xphx/7/.

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "John",

lastname: "Doe",

age: 32

}

},

 

render: function() {

return (

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

<div>

<h3 className="state-example">This is where all our component state will go </h3>

<p>firstname : {this.state.firstname}</p>

<p>lastname: {this.state.lastname}</p>

<p>age: {this.state.age} </p>

</div>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

Using this.state, we were able to render our initial state values. We can also send our initial state to props, so that other components can access our state value from SampleOneComponent. We will create a new React component called DataFromState and this will receive state values from SampleOneComponent to its props.

Code Example:https://jsfiddle.net/qtn6xphx/8/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "John",

lastname: "Doe",

age: 32

}

},

 

render: function() {

return (

<div>

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

<div>

<h3 className="state-example">This is where all our component state will go </h3>

<p>firstname : {this.state.firstname}</p>

<p>lastname: {this.state.lastname}</p>

<p>age: {this.state.age} </p>

</div>

<DataFromState thisState={this.state}/>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

var DataFromState = React.createClass({

render: function() {

return (

<div>

<h3>Our props from SampleOneComponent state</h3>

<p>firstname from SampleOneComponent state: {this.props.thisState.firstname}</p>

</div>

);

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

By passing this.state from SampleOneComponent as reference to thisState, we were able to receive data in our DataFromState component by this.props.thisState.

Next, let’s look into setting our state when there is a change in event. For our example, we’ll do a simple button, in which when clicked will set our one of state value.

Within our button element, we’ll have one of event listener onClick, which will listen for event when button is clicked. The button click event will invoke a function handleClick, which is just a method I created to change the state value when clicked. We use React’s this.setState() method change the state of SampleOneComponent’s firstname and lastname every time button is clicked.

Code Example:https://jsfiddle.net/qtn6xphx/10/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "Michael",

lastname: "Jordan",

age: 53

}

},

 

handleClick: function() {

if(this.state.firstname === "Michael" && this.state.lastname === "Jordan") {

this.setState({

firstname: "Kobe",

lastname: "Bryant",

age: 37

});

} else {

this.setState({

firstname: "Michael",

lastname: "Jordan",

age: 53

});

}

},

 

render: function() {

return (

<div>

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

<div>

<h3 className="state-example">This is where all our component state will go </h3>

<p>firstname : {this.state.firstname}</p>

<p>lastname: {this.state.lastname}</p>

<p>age: {this.state.age} </p>

</div>

<DataFromState thisState={this.state}/>

<div>

<button onClick={this.handleClick}>Click Me!</button>

</div>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

var DataFromState = React.createClass({

render: function() {

return (

<div>

<h3>Our props from SampleOneComponent state</h3>

<p>firstname from SampleOneComponent state: {this.props.thisState.firstname}</p>

</div>

);

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

Another important thing you can notice is that because the state from SampleOneComponent was passed as reference to DataFromState props, everytime state value changes, it will also update the change for the props that was passed.

As mentioned before, React’s state is rendered every change in event. For example, if we have a simple input box, React’s state will update every change in the input box. For example, if the user type’s “foo”, React’s state is updated three times because there is three letters inputted. Every letter input will update and render Reacts state and render function.

Explore React Courses

Let’s go ahead and create a input text field and a <p></p> tag to show display what’s typed in input text to show this example.

Code Example:https://jsfiddle.net/qtn6xphx/13/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "Michael",

lastname: "Jordan",

age: 53

}

},

 

handleClick: function() {

if(this.state.firstname === "Michael" && this.state.lastname === "Jordan") {

this.setState({

firstname: "Kobe",

lastname: "Bryant",

age: 37

});

} else {

this.setState({

firstname: "Michael",

lastname: "Jordan",

age: 53

});

}

},

 

render: function() {

return (

<div>

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

<div>

<h3 className="state-example">This is where all our component state will go </h3>

<p>firstname : {this.state.firstname}</p>

<p>lastname: {this.state.lastname}</p>

<p>age: {this.state.age} </p>

</div>

<DataFromState thisState={this.state}/>

<div>

<button onClick={this.handleClick}>Click Me!</button>

</div>

<div className="input-box">

<h3>Display state change of rendering</h3>

<form>

<input type="text" placeholder="type something here"/>

</form>

<p></p>

</div>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

var DataFromState = React.createClass({

render: function() {

return (

<div>

<h3>Our props from SampleOneComponent state</h3>

<p>firstname from SampleOneComponent state: {this.props.thisState.firstname}</p>

</div>

);

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

Now every time we type something in the input text box, React’s state will update upon every key press and change the state of our text and rendering it to our virtual DOM. We’ll need to first implement a custom method to handle the change in input text box. We’ll call this method onHandleChange() and we can create this just like a regular javascript function that will take an event as our parameter to grab the target’s value in input box. React also has onChange event listener, so we can use that on our input text box to invoke our onHandleChange() method.

Code Example:https://jsfiddle.net/qtn6xphx/14/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "Michael",

lastname: "Jordan",

age: 53

}

},

 

handleClick: function() {

if(this.state.firstname === "Michael" && this.state.lastname === "Jordan") {

this.setState({

firstname: "Kobe",

lastname: "Bryant",

age: 37

});

} else {

this.setState({

firstname: "Michael",

lastname: "Jordan",

age: 53

});

}

},

 

onHandleChange: function(e) {

console.log('event', e.target.value);

},

 

render: function() {

return (

<div>

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

<div>

<h3 className="state-example">This is where all our component state will go </h3>

<p>firstname : {this.state.firstname}</p>

<p>lastname: {this.state.lastname}</p>

<p>age: {this.state.age} </p>

</div>

<DataFromState thisState={this.state}/>

<div>

<button onClick={this.handleClick}>Click Me!</button>

</div>

<div className="input-box">

<h3>Display state change of rendering</h3>

<form>

<input

type="text"

onChange={ this.onHandleChange }

placeholder="type something here"

/>

</form>

<p></p>

</div>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

var DataFromState = React.createClass({

render: function() {

return (

<div>

<h3>Our props from SampleOneComponent state</h3>

<p>firstname from SampleOneComponent state: {this.props.thisState.firstname}</p>

</div>

);

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

Now that we know onHandleChange() method is being invoked and console logging every time we type something in our input text, let’s go ahead and change the state every time letter is typed. Just like before, we’ll use this.setState() method to update our state value input_text. Lastly, we’ll render our this.state.input_text below our input box so that we can see it render to DOM whatever we type.

Explore React Courses

Code Example:https://jsfiddle.net/cd5fsxut/2/

HTML

<div id=”sample”></div>

JavaScript

var SampleOneComponent = React.createClass({

getInitialState: function() {

return {

firstname: "Michael",

lastname: "Jordan",

age: 53

}

},

 

handleClick: function() {

if(this.state.firstname === "Michael" && this.state.lastname === "Jordan") {

this.setState({

firstname: "Kobe",

lastname: "Bryant",

age: 37

});

} else {

this.setState({

firstname: "Michael",

lastname: "Jordan",

age: 53

});

}

},

 

onHandleChange: function(e) {

e.preventDefault();

this.setState({

input_text: e.target.value

});

},

 

render: function() {

return (

<div>

<div>

<h1 className="sample-one"> this is sample one </h1>

<SampleTwoComponent

sampleString="this is string from sample one component"

sampleObject={ { text: 'object string'} }

sampleArray={ [1,2,3] }

/>

</div>

<div>

<h3 className="state-example">This is where all our component state will go </h3>

<p>firstname : {this.state.firstname}</p>

<p>lastname: {this.state.lastname}</p>

<p>age: {this.state.age} </p>

</div>

<DataFromState thisState={this.state}/>

<div>

<button onClick={this.handleClick}>Click Me!</button>

</div>

<div className="input-box">

<h3>Display state change of rendering</h3>

<form>

<input

type="text"

onChange={ this.onHandleChange }

placeholder="type something here"

/>

</form>

<p> {this.state.input_text} </p>

</div>

</div>

);

}

});

var SampleTwoComponent = React.createClass({

render: function() {

return (

<div>

<h2 className="sample-two"> this is sample two </h2>

<p className="sample-string">{this.props.sampleString}</p>

<p className="sample-object">{this.props.sampleObject.text}</p>

<p className="sample-array">{this.props.sampleArray[0]} : zero index</p>

<p className="sample-array">{this.props.sampleArray[1]} : first index</p>

<p className="sample-array">{this.props.sampleArray[2]} : second index</p>

</div>

)

}

});

var DataFromState = React.createClass({

render: function() {

return (

<div>

<h3>Our props from SampleOneComponent state</h3>

<p>firstname from SampleOneComponent state: {this.props.thisState.firstname}</p>

</div>

);

}

});

React.render( <SampleOneComponent />, document.getElementById("sample"));

React’s state and prop is the core of React. Having a good understanding of the concept will help you develop an awesome React application. It takes practice and understanding to get used to it, but once you grasp the basic idea, sky’s the limit. I hope that my explanation of state and prop can help you learn, understand, and develop something with React.

Explore React Courses

, , ,

Getting to know the ReactJS ecosystem – React and React Native

For new web developers, just learning javascript can be hard enough, let alone trying to understand the dozens of popular libraries, frameworks, services, architectures, preprocessors, bundlers, and other technologies in wide use today. It can all make web development seem esoteric and inaccessible. If you feel this way, you are not alone!

I’m here to help by providing an introduction to a thriving avenue of one part of the web world: ReactJS. Rather than attempt to create a comprehensive guide, I thought it would be beneficial to provide a high-level introduction with links to resources for learning more. Consider this step 1 on your journey to becoming a React guru.

Explore React Courses

ReactJS

React (React or React.js) is an open source view rendering library originally developed at Facebook. The motivation behind React is to make the UI more predictable by establishing a hierarchy of modularized components. A simple component consists of DOM elements that describes its structure, plus any supporting data and methods. React restricts how components store and exchange data with state and props. A component’s state consists of all the data necessary to define a component’s appearance and behavior, while props refers to the data (properties) assigned to a child component by its parent. When something in the application changes, it typically corresponds to a change in state, which triggers React to re-render and make the change. React takes care of all the event listening/delegation and allows the developer to instead focus on what the application should look like given a particular state.

Explore React Courses

component_relationship

Parent-Child Relationship

Here’s a simple example:

See the Pen Simpler React Example by Mike (@qualitydixon) on CodePen.

The whole of the application is one component that displays a number and two buttons that increment or decrement the number. Let’s go over the fundamental pieces. Take a look at the first line:

var AdjustValue = React.createClass({

createClass is the entry point for creating a React component and inside createClass is where a component’s appearance and behavior is specified. To begin, the component’s state is defined with:

 getInitialState: function() {

   return {

     counter: 10

   };

 }

In this case the state contains one item counter, whose value is set to 10. After that a function is defined:

shift: function(x) {

   this.setState({

     counter: this.state.counter + (x)

   })

 }

The only action of shift is to call setState and update counter. setState is the main method used to notify React that something has changed and the UI may need to update.

The last piece of the component, the implementation of the render method, is the most important. This is where the component’s DOM subtree is defined. Look at how that’s done for AdjustValue:

render: function() {

   return (

     <div className="adjustValue">

       <button id="minus" className="btn glyphicon glyphicon-minus" onClick={this.shift.bind(this, -1)}></button>

       <div> {this.state.counter} </div>

       <button id="plus" className="btn glyphicon glyphicon-plus" onClick={this.shift.bind(this, 1)}></button>

     </div>

   );

}

render returns the DOM elements that make up the component. Notice how the elements are constructed as they would be in an HTML document. This is made possible by React’s use of a javascript preprocessor called JSX. It allows for XML-ish syntax to be written directly in javascript files. JSX is not required to use React but makes for a very clean, readable way to define DOM elements.

The shift function is set to the onClick events of the buttons. When the user clicks the button, a setState event is triggered, telling React it needs to update. Here’s an overview highlighting major component building blocks:

Explore React Courses

component_anatomy

Anatomy of a React component

Finally, all that’s left is to insert AdjustValue into the DOM. Consider the last line in the example:

React.render(<AdjustValue />, document.getElementById('root'));

React.render is how components get rendered into the DOM. It takes in the component to be rendered (which in itself can be a hierarchy of components), and the location in the document to mount the component to, in this case ‘root’.

At this point it still may be unclear why you would choose ReactJS over any other library or framework so, equipped with our new knowledge of how ReactJS works, allow me to point out some benefits.

  • Reusable components. Define it once and use it again and again.
  • Components bring together elements and the methods that affect them. No more switching back and forth between HTML and JS files trying to decipher the behavior and relationships of elements.
  • ReactJS encourages purity. A pure function will always return the same output for a given input. The result does not depend on anything except the parameters it is provided. Similarly, If you provide your ReactJS application with a particular state you will get the same outcome 100% of the time. This is hugely beneficial for the predictability, and testability, of your application.
  • Performance. ReactJS is the middle-man between you and the DOM. When an action is triggered, it calculates the minimal amount of steps needed to reflect UI changes. And since it’s traditionally DOM updates that bottleneck app performance, the resulting bump in efficiency is noticeable.

Digging Deeper

If you’re ready for more, I suggest starting with the official documentation, which is well written and has plenty of guides and examples. Also take a look at the official ReactJS GitHub repo. In addition, I found the following resources to be helpful:

React Native

React was conceived, and is most often used, for rendering HTML. However, the beauty of React is that it can be applied to other view systems. That’s where React Native comes in. React Native is Facebook’s effort to bring the benefits of React into native app development (i.e. Android or iOS). I think React Native is best understood by looking at an example and comparing/contrasting it to React. Here’s the same AdjustValue component created in React Native for Android:

import React, {

 AppRegistry,

 Component,

 StyleSheet,

 Text,

 TouchableHighlight,

 View

} from 'react-native';



var AdjustValue = React.createClass({

 getInitialState: function() {

   return {

     value: 10

   };

 },

 shift: function(x) {

   this.setState({

     value: this.state.value + (x)

   })

 },

 render: function() {

   return (

     <View style={styles.container}>

       <TouchableHighlight underlayColor={'#396a73'} onPress={this.shift.bind(this, -1)}>

         <Text style={styles.adjustValue}> - </Text>

       </TouchableHighlight>

       <Text style={styles.adjustValue}>

         {this.state.value}

       </Text>

       <TouchableHighlight underlayColor={'#396a73'} onPress={this.shift.bind(this, 1)}>

         <Text style={styles.adjustValue}> + </Text>

       </TouchableHighlight>

     </View>

   );

}

});
const styles = StyleSheet.create({

 container: {

   flex: 1,

   flexDirection: 'row',

   justifyContent: 'center',

   alignItems: 'center',

   backgroundColor: '#3F51B5',

 },

 adjustValue: {

   fontSize: 30,

   textAlign: 'center',

   color: 'white',

   margin: 10,

 },

});


AppRegistry.registerComponent('AdjustValue', () => AdjustValue);

For the sake of completeness, here’s what that component looks like on an Android emulator:

react_native_example_screen

Compare and contrast this AdjustValue component with the one written for the web. The component itself is defined in the same way, using React.createClass. The state of the component and functions are also defined in the same way. The heart of the distinction is in the implementation of render. View and TouchableHighlight take the place of div and button. Now we’re rendering Native elements instead of DOM elements (or more precisely, wrapped up Native elements). With React Native you get the best of both worlds. The structure and flow of React with the performance advantages for mobile. Plus a common development environment across multiple platforms, allowing a company to potentially collapse their web, android, and iOS teams into one.

Explore React Courses

Digging Deeper

There’s not a great deal of educational content specific to React Native but remember much of the ReactJS documentation applies to React Native as well. That being said, if you want some perspective on the goals and motivations behind React Native, check out this excellent blog post by Facebook engineer Tom Occhino. After that, there’s always the official React Native site. And of course the GitHub repo.

That’s it for now. Check back as we dive deeper into the React-verse with an introduction to webpack, flux, redux, relay, and more!