A React App Infinite Scroll Slider

Recently I’ve been learning about the React framework coming from a AngularJS background. My day job still relies on AngularJS and I haven’t had the chance to get into building any applications with React. Finally I decided it was time to dig in for myself and start building some React components. In order to get myself familiar with the React library I decided to build an infinite scroll portrait slider. In this article I will walk through the code and the logic. All the code for the slider can be found here and you can take a look at the demo on this page.

Setup

We’re going to build this app using create react app which will let us quickly bootstrap a React app. If you haven’t done so install create react app using npm.

npm install -g create-react-app

Let’s create our react app folder

create-react-app react-slider
cd react-slider

Delete the files App.css, App.js, App.test.jsand create new files slider.js, slide.js and slider.css. Our main component will be Slider and we need to update index.js to import and use our main component.

import Slider from ./slider

Let’s update the main render function to use our new slider.

ReactDOM.render(<Slider />, document.getElementById(‘root’));
registerServiceWorker();

The new index.js should now look like the following.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Slider from './slider'
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<Slider />, document.getElementById('root'));
registerServiceWorker();

Slider Component

Now let’s move on to our slider.js file and build our slider. We’ll need some css for our slider and we can create slider.css for that purpose. Let’s put in place the basic setup for our component and build it up from there.

import React, { Component } from 'react';
import Slide from './slide'
import './slider.css'
export default class Slider extends Component {
constructor(props) {
super(props)
}
render() {
return (
)
}
}

This is a basic setup where we import the react component and create our slider class that extends Component. We have a constructor method and a main render method. For our slider we need to render our slides and we also need arrows for navigation. We’re going to put those in their own render functions. Let’s update our main render method to reflect our new render functions.

render() {
return (
<div className="slider">
{this.renderNavigation()}
{this.renderSlides()}
</div>
)
}

The renderNavigation() function will output our two navigation arrows for moving the slide left and right. We’ll use images for the arrows and we can put that in an img folder.

renderNavigation() {
return (
<div className="slider-arrows">
<a className="arrow left">
<img src={require('./img/arrow-left.png')} />
</a>
<a className="arrow right">
<img src={require('./img/arrow-right.png')} />
</a>
</div>
)
}

We use a parent div to hold our two left and right arrows and make them links with images. In order for these arrows to be places correctly on the page we’ll need to update our slider.css.

.slider-arrows {
position: absolute;
width: 100%;
z-index: 3;
}
.slider-arrows > .arrow {
margin-top: 300px;
}
.slider-arrows a {
cursor: pointer;
display: block;
opacity: 0.8;
position: absolute;
}
.slider-arrows > .arrow.right {
right: 0;
}

We do an absolute positioning of the arrows with a margin-top of 300px to place it in the middle of the slides. The right arrow is move to the right of the page and we use a cursor point for both links. Now we are ready to render our slides.

In order to render our slides we’ll need some images. I downloaded some nature images and you can use your own favorite images. Place the images in the img folder and let’s update our constructor function with an array that hold a reference to the images. We’ll also want to set width and height for the images as well.

export default class Slider extends Component {
constructor(props) {
super(props)
this.state = {
width: 300,
height: 800,
images: ['nature-1.jpg', 'nature-2.jpg', 'nature-3.jpg', 'nature-4.jpg', 'nature-5.jpg', 'nature-6.jpg']
}
}

Our renderSlides() function will loop through the images and output each image into a Slide component that we will build. Let’s take a look at this code.

renderSlides() {
const images = this.state.images;
return (
<div className="slider-items">
{
images.map((image, index) => {
return (
<Slide image={image} width={this.state.width} height={this.state.height} key={index} />
)
})
}
</div>
)
}

We use a map function to loop through the images array and render a slide component in which we pass the image name, width and height as props. React loops require a unique key and in this case we use the index. We could alternatively use the image name for the key as well.

Slide Component

Let’s take a look at the Slide component that we need in slide.js file. We’ll need to take in the props and output the slides using the background images with the width and height. In the case that the width and height is not passed down we’ll set a default as well. We are creating this component as a stateless function. Here is the code for the slide.js.

import React from 'react';
import PropTypes from 'prop-types';
const Slider = ({image, width, height}) => {
const backgroundImage = require(`./img/${image}`);
const styles = {
backgroundImage: `url(${backgroundImage})`,
backgroundPosition: 'center top',
backgroundRepeat: 'no-repeat',
float: 'left',
width: `${width}px`,
height: `${height}px`
}
return (
<div className="slide" style={styles}></div>
)
}
Slider.defaultProps = {
width: 300,
height: 600
}
Slider.propTypes = {
image: PropTypes.string.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired
}
export default Slider;

Slider Navigation

Now we can move on to our navigation of the slides. We’re building an infinite scroll slider which means that as we move past our last slide the first one should come back. The same goes if we move in the other direction going backwards as as the last slide would show when we move past the first slide. Let’s create two function for moving left and right.

slideLeft() {
}
slideRight() {
}

Every time we slide left we are moving backwards. In this case we need to take the last slide and move it and make it the first slide bumping the other slides over. We’ll use a combination of array slice and new ES6 array constructor syntax to accomplish this task. We can get the last slide by using a slice.

let last = this.state.images.slice(-1)

Now we need all the rest of the slides except the last one.

let rest = this.state.images.slice(0, -1)

Now we can construct a new array moving the last one first and adding the rest and update our state variable.

let images = [last, ...rest]
this.setState({images: images});

When we are navigating to the right we want to do the opposite. We need to take the first slide and move it to the last. We can do this a bit easier using new ES6 array constructor and de-constructor syntax.

let [first, ...rest] = this.state.images;
let images = [...rest, first];
this.setState({images: images});

Now that we have our navigation functions we’ll need to update our arrow function with onclick methods to use the new functions.

renderNavigation() {
return (
<div className="slider-arrows">
<a className="arrow left" onClick={() => this.slideLeft()}>
<img src={require('./img/arrow-left.png')} />
</a>
<a className="arrow right" onClick={() => this.slideRight()}>
<img src={require('./img/arrow-right.png')} />
</a>
</div>
)
}

In order to finish up the slider we can a bit of animation to our slides using css.

.slider .slide {
-webkit-transition: 0.5s;
-moz-transition: 0.5s;
-o-transition: 0.5s;
transition: 0.5s;
}

Finished!

That’s it! We now have a fully functional infinite scroll slider using React. I have found React to be a great library that allows you to quickly build components like this in very little time.

If you like this article give a bit of love on Medium and don’t forget to share. I welcome comments and suggestions on the article or about the code. If you like this slider feel free to fork it or contribute if you think it can be better.

Show your support

Clapping shows how much you appreciated Arash Soheili’s story.