Free eBook: Build Your First Node App

Build an Image Slider Using React, Superagent and the Instagram API

Jacky Kimani
👁️ 2,306 views
💬 comments

Introduction

You've probably used many different libraries to make Ajax calls. Fetch API, Axios, Request, jQuery $.ajax and SuperAgent are some of the most popular ways to fetch data from an API. However, we'll only be focusing on SuperAgent in this tutorial.

Do you need to create an image slider for a website you're creating, say to market a number of products from your Instagram, or just want to learn how to create one? Then you're in the right place! We'll be building an image slider with images from your Instagram and using SuperAgent to fetch those images.

Setting up the project

For simplicity, we'll be using create-react-app to set up our project. It will help us to avoid webpack and focus on the React side of things.

Table of Contents

    Start off by running the command on your terminal.

    create-react-app image_slider

    The result will be a project folder named image_slider (to use another name, simply replace image_slider on the terminal with your preferred name). The project folder should contain important files including the package.json, node_modules and our src folder which is where our app files will live.

    On your terminal, start the app to make sure everything works perfectly by running the command below.

    yarn start

    This should open the URL http://localhost:3000/ on our browser. Any changes that we make to our React files will automatically make our page reload on the browser.

    Setting up React

    You should notice that we already have our react dependencies installed for us on our project. We'll dive into editing our component. For simplicity we'll be using just one file for our project. Feel free to have the various components we'll be creating on seperate files but ensure to export and import them correctly.

    For this app, I chose to keep the header but change the wording. Go ahead and delete the <p></p> tag as we won't need it here, unless you need to do a small introduction for your app. You'll notice, as I mentioned before, the browser automatically changes when you make changes to your file and save it.

    At this point, your App.js file should look like this

    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './App.css';
    
    class App extends Component {
      render() {
        return (
          <div className="App">
            <header className="App-header">
              <h1 className="App-title">My Instagram</h1>
            </header>
          </div>
        );
      }
    }
    
    export default App;

    Setting up SuperAgent

    As defined on its documentation, SuperAgent is a light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve. It's a simple and easy to learn library.

    A request made should have the method or action that you'd like to perform, followed by a .then() or .end() function to perform operations on/with the response. You can include a .catch method for error handling but this is optional.

    A basic request would then look like this

    request
      .get('/getsomedata')
      .then((res) => {
        console.log(res)
      }
      .catch((err) => {
        console.log(err)
      }

    Start off by installing superAgent. Run yarn add supertest on the terminal. Next, import it on our App.js file after which we'll start fetching the data from the Instagram API

    import React, { Component } from 'react';
    import request from 'superagent';
    import logo from './logo.svg';
    import './App.css';
    
    class App extends Component {
      constructor(props) {
        super(props);
        this.state = {
          photos: []
        }
      }
    
      componentWillMount() {
        this.fetchPhotos();
      }
    
      fetchPhotos() {
        request
          .get('https://api.instagram.com/v1/users/self/media/recent/?access_token=ACCESS-TOKEN')
          .then((res) => {
            this.setState({
              photos: res.body.data
            })
          })
      }
    
      render() {
        return (
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <h1 className="App-title">Welcome to My Instagram</h1>
            </header>
            <div>
              {console.log(this.state.photos)}
            </div>
          </div>
        );
      }
    }
    
    export default App;
    

    We'll create a function named fetchPhotos which will be responsible for fetching data. Once it GETs the data, it is stored in an array called photos which is in the state. The fetchPhotos function is called right before the component mounts using componentWillMount. For now, we'll be logging the array to see whether we have fetched the data. We have not done any authentication yet so we shouldn't be able to see anything, instead it should give us a 400 error message.

    Instagram API

    The Instagram API will be providing us with the photos we'll be using to create our slider. Since we're only working on the client side and not focusing on how to use the Instagram API, we don't have to go through the authentication process to get our access token. However, if you'd like to learn more about how to use the Instagram API, you can go through their documentation or this detailed tutorial here

    For us, you can generate a token from this website here. Be sure to have the token in a .env file to avoid sharing it.

    Creating the Image Slider

    Displaying the images

    The photos that we fetched are contained in an array but we need to display each one of them as a single photo. Therefore, we'll need to write a map function to loop through the array and return our photos which will all be displayed on our page.

    Before adding our photos onto our page, we can try logging the photo onto the browser's console by adding this line inside the map function {console.log(photo)}. This will give us an object that contains a number of attributes, a few being images, captions, created_at date, likes, comments, people tagged on the photo etc.

    Our new function will be inside a new div under our header and should look like this:

    <div>
      {this.state.photos.map((photo, key) => {
        return (
          <div key={photo.id}>
            <img src={photo.images.standard_resolution.url} alt={photo.caption}/>
          </div>
        )
      })}
    </div>

    We'll also be displaying the captions from our photos on the bottom of the photos. To do this we'll need to add another div below the image tag. Feel free to change the styling on our div. In case the photo had no caption on Instagram, to avoid any errors, we'll instead return an empty string, hence the conditional statement.

    <div style={{width:'600px', margin: '24px auto', fontStyle: 'italic'}}>
      {photo.caption !== null ? photo.caption.text : ''}
    </div>

    Adding the slider arrows

    So far all the photos we fetch from the Instagram API will be displayed on the same page together. This is not what we want. Our next step is to display each photo separately and add navigation from one photo to the other.

    We'll definitely need arrows to navigate through the slider. For this we'll include two arrows as separate components like this

    const BackArrow = () => (
      <div style={{fontSize: '2em', marginRight: '12px'}}>
        <i className="fa fa-angle-left fa-2x" aria-hidden="true"></i>
      </div>
    )
    
    const NextArrow = () => (
      <div style={{fontSize: '2em', marginLeft: '12px'}}>
        <i className="fa fa-angle-right fa-2x" aria-hidden="true"></i>
      </div>
    )

    Create-react-app does not have the script we need to use font awesome icons so we'll need to run yarn add font-awesome to add it to our project then import 'font-awesome/css/font-awesome.css' to include our icons.

    Adding slide count to state

    What we have now is all the components we'll need but the arrows are not functional and all our photos are still visible on our page.

    Add slideCount to our state to keep track of which photo we are on. slideCount will simply be an integer which is initially set at 0 and is incremented each time we click on the next arrow and decremented when we click on the previous arrow.

      constructor(props) {
        super(props);
        this.state = {
          photos: [],
          slideCount: 0
        }
      }

    To display a single photo at a time, we'll need to check the index of the photo and display the photo that matches the slide count on our state. This should be inside our map function like so

    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <h1 className="App-title">Welcome to My Instagram</h1>
      </header>
      <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center',marginTop: '30px'}}>
        {this.state.slideCount !== 0 ? <BackArrow previousImage={this.previousImage}/> : ''}
        {this.state.photos.map((photo, key) => {
           if (this.state.photos.indexOf(photo) === this.state.slideCount) {
             return (
               <div key={photo.id} style={{margin: '0 auto'}}>
                 <img src={photo.images.standard_resolution.url} alt=''/>
                 <div style={{width:'600px', margin: '24px auto', fontStyle: 'italic'}}>
                   {photo.caption !== null ? photo.caption.text : ''}
                 </div>
               </div>
             )
           }
         return ''
       })}
       {this.state.slideCount !== (this.state.photos.length - 1) ? <NextArrow nextImage={this.nextImage}/> : ''} </div>

    We're including an if statement when calling our BackArrow component because we don't want to see it when we're on the first photo. Similarly, we don't want to see the NextArrow when we're on the very last photo.

    At this point since our state is 0, the browser should display one image (the very latest on the Instagram account) and the next arrow.

    Making the arrows functional

    To get our arrows working, we'll need to create functions that change the current photo we're viewing. The 2 functions will either increment the state's slideCount or decrement it to change the photo being displayed

    nextImage() {
        this.setState({ slideCount: this.state.slideCount + 1 })
      }
    
      previousImage() {
        this.setState({ slideCount: this.state.slideCount - 1 })
      }

    We'll need to add an event handler that calls these functions whenever the arrows are clicked. Add the onClick event to the 2 arrow components we created.

    const BackArrow = (props) => (
      <div onClick={props.previousImage} style={{fontSize: '2em', marginRight: '12px'}}>
        <i className="fa fa-angle-left fa-2x" aria-hidden="true"></i>
      </div>
    )
    
    const NextArrow = (props) => (
      <div onClick={props.nextImage} style={{fontSize: '2em', marginLeft: '12px'}}>
        <i className="fa fa-angle-right fa-2x" aria-hidden="true"></i>
      </div>
    )

    Remember to pass the 2 functions as props from the parent component.

    <BackArrow previousImage={this.previousImage}/>
    <NextArrow nextImage={this.nextImage}/>

    To have access to the functions we'll need to bind the functions to the component instance (this)

    this.nextImage = this.nextImage.bind(this);
    this.previousImage = this.previousImage.bind(this);

    There we go! We should have a functional image slider now!

    Conclusion

    Using SuperAgent as a request library is super easy and efficient at the same time. We can expand our app by trying to use the send, set, redirects or auth methods. At the same time you can create different custom URLs and use the post, delete and put methods to add, remove and edit images or captions respectively.

    Jacky Kimani

    2 posts

    Software Developer at Andela

    I am a Javascript developer who never stops learning! I believe in helping others get to where I am and beyond