Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / React

How to Build a React App Using a Mock Contacts API

5.00/5 (3 votes)
8 Jan 2018CPOL6 min read 18.1K  
This tutorial teaches you how to build a React application from scratch. In addition, we will be using fetch API with React to make asynchronous calls to a mock server.

React is a popular front-end JavaScript technology for creating interactive user interfaces. You can use the React library to build a robust and modern web/mobile application without having much consideration about the backend. You can build anything from a to-do list app to something gigantic app like Facebook. Today, I am going to take you through the steps for building the front-end of a contacts application. The app will be connected to a contacts API endpoint for the backend. This tutorial should also help you get started with using Fetch API with React.

Overview and Prerequisite

We’re going to cover two things in this tutorial.

  1. How to create a React application?
  2. How to make the frontend and the API endpoints meet?

The second point is something seldom covered in a React tutorial. We’re going to bridge that gap by creating a basic application that retrieves data from a contacts API server. For the purpose of demonstration, I am going to use a mock API service. However, you can make your application practically useful by using actual contact APIs such as Google API, Lusha’s contact API, etc. They’re free and practically useful too.

The code for this tutorial is available in my Github repository. I’ve also set up a live demo on codesandbox.

create-react-app is my first preference tool for creating a React application from scratch. Install create-react-app if you haven’t already.

npm install create-react-app

Now, create a new project as follows:

create-react-app contact-list

Start the server using yarn start.

Structuring the Application

Here is what we want the application to look like. A search bar on top and the contact list takes up the rest of the screen. I will be using Bootstrap and Font Awesome icons for the styling.

An image of the contact list application

Here is how I want our app to work. Initially, the view will retrieve all contacts from the server and display them. You can then use the search bar to search for contacts using their name or phone number.

We can split the entire structure into three components, two of which are reusable -- the App component, the SearchBar component and the ContactCard component.
Here is how the app component is going to look like:

JavaScript
class App extends Component {
.
.
render() {
return(
    <div className="row">
      <div className="col-xs-12 col-sm-offset-3 col-sm-6">
        <span className="title">Contacts</span>
          <SearchBar />
    <ul cl assName="list-group" id="contact-list">
         <li className="list-group-item"> 
           <ContactCard />
         </li>
        </ul>
     </div>
   </div>
  )
}

Retrieving the Contacts from Contacts API

Let’s add some state. We’ve initialized the state object which includes searchText, searchResult, and contactList.

JavaScript
constructor(props) {
    super(props);
    this.state = {
      searchText: '',
      searchResult: [],
      contactList: []
    }

Next up, we’re going to retrieve all contacts from the server. I’ve set up a mock API at mockable.io to simulate a real contacts API. The API returns the following JSON when a GET request is made. You can try it yourself.

JavaScript
{ "code": 200,
  "contacts":[
  {
    "name": "Mark",
    "surname": "Cook",
    "gender": "male",
    "address": "52 East Forest Rd. mRockford, MI 49341",
    "age": 27,
    "title": "mr",
    "phone": "(396) 881 3396",
    "birthday": {
      "dmy": "09/08/1990",
      "mdy": "08/09/1990",
      "raw": 650246246
    },
  }, 
 ...
 ]
}

Since we need to retrieve the contacts when the component mounts for the first time, I am going to use the componentWillMount lifecycle method. First, create a constant that holds the contacts API.

JavaScript
const contactsAPI = 'https://demo1443058.mockable.io/codeproject_tutorial/api/contacts';

Now, define the componentWillMount() method as follows:

JavaScript
componentWillMount() {
    let init = {
         method: 'GET',
         headers: new Headers(),
         mode: 'cors',
         cache: 'default' 
      };

    fetch(contactsAPI, init)
      .then( response => response.json())
      .then( 
        data => this.setState( 
          prevState => ({
          contactList: [...data.contacts]
          }) 
      )
    )
}

The fetch() method accepts two parameters, the API URL and an optional object that you can use to define certain additional properties. fetch() returns a promise and you can chain multiple promises as we did here. We first convert it into a JSON object and move the fetched data into the state so that we can use it in the render method.

Displaying the Contact Data

We’ve ensured that the data is fetched from the contacts API and stored in the state when the App component mounts. Now, we need to pass down the data to Contactcard component.

HTML
<ul className="list-group" id="contact-list">
           { this.state.contactList().map(
               (contact) =>
                 <li key={contact.email} className="list-group-item">
                   <ContactCard contact = {contact}/>
                 </li>
             )
           }
</ul>

The contact information is available at props.contacts. You can destructure the props as I did below to make the code more readable. The data stored in contact.name, contact.surname, contact.phone, contact.email and contact.address are being displayed. I’ve used some extra CSS styles and HTML to make the contact card look good.

JavaScript
  const ContactCard = ({contact}) => {
    return(
       <div>
            <div className="col-xs-4 col-sm-3">
                <img src={contact.photo} alt={contact.name + ' ' + contact.surname} 
                                         className="img-responsive img-circle" />
            </div>
            <div className="col-xs-8 col-sm-9">
                <span>{contact.name + ' ' + contact.surname}</span><br/>
                
                <span title={contact.address}></span>
                <span>{contact.address}</span><br/>
                
                <span title={contact.phone}></span>
                <span>{contact.phone}</span><br/>
                
                <span title={contact.email}></span>
                <span>{contact.email}</span><br/>
            </div>
            <div className="clearfix"></div>
       </div>        
    )
}

Searching through the Contact List

For searching contacts, we already have a SearchBar component. Here is an outline of how the search feature should be implemented:

  1. The SearchBar component hosts the UI for the search bar which includes an input control field.
  2. When the input field changes, it triggers the onChange event.
  3. The onChange event executes the parent component’s callback and the input control value is passed as an argument.
  4. The parent component, which is the App component in our case, has a handleSearch method.
JavaScript
const SearchBar = ({onSearch}) => {
    const handleChange = (e) => {
        onSearch(e.target.value);
    }
    return( 
        <div className="input-group ">
            <input onChange = {handleChange} className="form-control" 
             type="search" placeholder="Search for a contact" id="example-search-input" />
            <button className="btn btn-default" type="button">
                <i className="fa fa-search"></i>
            </button>
        </div>
    )
}

And here’s the props for the callback.

HTML
<SearchBar onSearch={this.handleSearch} />

For the search logic, there are many ways in which you could approach this. Here is the one which I think is easiest to implement.

  • Clear the state of the searchResult array so that the results from the previous search don’t show up.
  • Each contact in the contact list is mapped using the map method and is passed as an argument to the searchContact function along with the searchText.
  • The searchContact function checks whether the name, email or the phone attribute of the contacts matches the searchText.
  • JavaScript’s String.prototype.search() is used to compare the strings and if a match is found, -1 is returned.
  • If a contact is matched, store it in the state.

Here’s the code for handleSearch() and the logic for searching individual contacts.

JavaScript
 handleSearch(searchText) {
   
    this.setState({searchResult: [], searchText: searchText});
    this.state.contactList.map(contact => {
    
    if(searchContact(contact, searchText)) {
         this.setState( prevState => ({
           searchResult: [...prevState.searchResult, contact]
         }), () => console.log(this.state.searchResult))
      }
    })
  }
...
/* searchContact function */
 const searchContact = (contact, searchText) => ( 
     contact.name.toLowerCase().search(searchText.toLowerCase()) != -1 || 
     contact.surname.toLowerCase().search(searchText.toLowerCase()) != -1 || 
     contact.phone.toString().search(searchText) != -1 
 )

Querying the Contacts API for the Search Term

Alternatively, you might want to query the API directly for the search term on each keystroke or after a submit button is pressed. This is more expensive, but if the contacts API is like a telephone directory in the cloud, here is something you could do. I will encourage you to experiment this part yourself.

  1. Clear the state of the searchResult similar to what we did earlier.
  2. Using fetch, send a GET request to the server with the searchText appended like this.
  3. GET https://api.example.com/person?firstName=`${searchText}`
  4. Store the response in this.state.searchResult

If you need to search the surname and the phone number, you might have to make multiple API calls and append the results to the state.

We’re nearly done with contacts application. However, the search results don’t appear on screen yet. This is because we haven’t yet supplied the searchResult to the ContactCard component. We could do something like this:

HTML
<ul className="list-group" id="contact-list">
            { this.state.searchResult().map(
                (contact) => 
                  <li key={contact.email} className="list-group-item"> 
                    <ContactCard contact = {contact}/>
                  </li>
              )
            }
</ul>

However, the component won’t fetch the contacts from the server when the component mounts. To fix this, create a new method or use a ternary operator that does the following:

JavaScript
returnContactList() {
   return this.state.searchText ? this.state.searchResult :this.state.contactList
  }

And let returnContactlist() decide which list to return. Here is the final version of the code.

HTML
<ul className="list-group" id="contact-list">
            { this.returnContactList().map(
                (contact) => 
                  <li key={contact.email} className="list-group-item"> 
                    <ContactCard contact = {contact}/>
                  </li>
              )
            }
</ul>

Voila! We have our own working contacts app built using React.

Summary

We’ve built a contact list application from scratch in about 30 minutes. That’s a remarkable feat on its own. Apart from that, we’ve also learned how to make API requests using React and use the returned data in a meaningful way. What are your thoughts about React as frontend library? Let me know them through the comments.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)