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

PostedDecember 12, 2019 1.5k views JavaScript

While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Introduction

In this tutorial you will build an image slider with images fetched from Instagram using SuperAgent. There are many different libraries that can be used 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.

Specifically, you will create an image slider using the [reactjs](reactjs.org/) JavaScript framework. It will display images from Instagram that are fetched using the SuperAgent Ajax request library.

Prerequisites

To follow this tutorial, you will need nodejs installed locally on your computer. You will also need to install Create React App.

Once you have those requirements installed, begin by setting up your project workspace.

Setting up the project

The create-react-app command is a convenient way to set up our project. It will help configure dependencies and leave you to focus on the React side of things.

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 will contain important files including package.json, node_modules and our src folder which is where our app files will live.

In 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 you make to the React files will automatically make the page reload in the browser.

Setting up React

All the react dependencies that we need are already installed for us. For this tutorial, only one file will be edited in the project. Feel free to separate the various components that you create live in seperate files if you prefer. If you do, ensure to export and import them correctly.

To get started, edit App.js and delete the <p></p> tag as it is not needed, unless you want to write a small introduction for your app. Notice that the browser automatically reloads 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.

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 GET 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 and edit the file to look like the following:

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;

The function named fetchPhotos is responsible for fetching data from Instagram. 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 provide the photos to display with the slider we’re creating. 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.

You can generate a token using http://instagram.pixelunion.net. 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>

The slider will also display the captions for photos on the bottom of the photos. To do this, add another div below the image tag. Finally to avoid any errors in case the photo has no caption on Instagram, add a conditional that returns an empty string:

<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 fetched from the Instagram API will be displayed on the same page together. The next step is to display each photo separately and add navigation from one photo to the other.

Arrows are a useful way to navigate through the slider. For this functionality, 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 you will need to run yarn add font-awesome to add it to the 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, 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 this:

<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 the arrows working, create two functions that will change the current photo that is being viewed. The 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 also 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);

At this point, you should have a fully functional image slider.

Conclusion

In this tutorial, you learned how to use SuperAgent as a request library in combination with React to build an interactive image slider. With this set of tools in place, you could also expand the slider to incorporate other functionality like creating different custom URLs and use the post, delete and put methods to add, remove and edit images or captions respectively.

0 Comments

Creative Commons License