How to create a small automatic carousel with React without external libraries.

Rodolphe A
Dev Genius
Published in
8 min readMay 29, 2022

--

A few months ago, I created a carousel for one of my projects, as I have a preference to build from scratch rather than choose an npm package, (I find that clean from scratch code has a much better maintainability and durability than a quick npm package) for a specific use.
When a feature needs to be specific to something, it’s better to develop the feature yourself than to choose an external solution that probably won’t fit the future changes in time of this feature, or won’t guarantee that this package will be flawless or still under development in 6 months.

So, let’s develop this project from scratch…

This tutorial being a javascript tutorial, the css will only be discussed briefly and the media queries section is not aborded at all here.

What will we develop today?

This is what we will create.

The carousel contains two categories, “sports car brands” and “electric car brands”.

In the sport category, there are four images and text…
and in the electric category, there are three images and text

The carousel is automatic, but the categories are clickable!

Let’s get started…

First, I create a react app with the command:

npx create-react-app automated-carousel

Here we are with a basic app like this:

yarn start or npm start to run dev server

Let’s start by creating some folders in order to architect our project.

In the src folder of the project I create an assets folder, which contains two folders, the first named “electricCars” and the second “sportCars”.
then, in the same folder ( /src) I create a components folder and another hooks folder.

The structure of our project is ready, let’s import the images now…

The link to the “electric” logos:

The link to the “sport” logos:

Then, in the assets folder (next to the two folders it contains) I create a file that I name picturesExport.js.
This will make importing images into my components easier and faster.

The content of this file is relatively simple, I import the images then I export the variable that represents the image.

After that, I create a data.js file in the /scr folder, to create two arrays of objects representing the categories.

Each object consists of an id, an image, a text and a width.

As you can see, concerning the import of images in this file, I only import the variables of the export file created in the previous step. This makes the code much more readable and clean.
Let’s continue…

Now I will create two components, one named Banner.js and another named Slider.js

The Banner component base look like this:

And the Slider component look like this:

Then, in the App.js file, I replace the default content with this one:

Let’s create some style in the App.css file,

Replace the content of this file by default with this one:

As this article is about the development of an automatic carousel, the css will not be explained in details because you can “do it your way in multiple ways”, on the contrary, I will explain the operation of React, The principle of separation of concern and reusable components. That will be enough for this time.

And, the result at this level of the project, looks like this:

As you can see, the text of the two categories overlap,

this is due to the absolute position and the text-align:center of the ul, this is exactly what we want at this stage of development.

Next step…

We will now create a reusable component that will be used to display our logos by category.

Let’s create a file named CarBrandsSlide.js
Add the content below:

Code explanation:

This component takes one argument as props, this argument is an array (dataArray).
Then I map the array, I define a key, I place my image with the width as style, and finally I create a h4 tag which contains the text.

I go back to my Silder.js component to import my reusable component (CarBrandsSlide) with as respective props, sportCarsArray and electricCarsArray, not forgetting to define an id to each ul that contains the component, “ListSport” for the component that renders the list of sport brands and “ListElectric” for the other.

Then, of course I import my arrays from the data file created before.

Ok, at this stage, no images appear, it’s normal, the css code is in place but not yet the logic…

so, let’s create a custom hook useSliderAnimated.js to implement the necessary logic.

The content of this file it’s:

Code explanation:

First, I create 4 states, 2 boolean (for the “click” action of each category) and 2 strings which will contain the name of the classes to apply according to the animation (entry or exit of the screen)

const [clickedSportCars, setClickedSportCars] = useState(true);const [clickedElectricCars, setClickedElectricCars] = useState(false);const [sportListClassName, setsportListClassName] = useState("");const [elecListClassName, setelecListClassName] = useState("");

As you can see clickedSportCars is set to true while the other category is set to false as default value.

Then I implement a handleClickAction function, which just changes the state from true to false and from false to true on both categories simultaneously.

const handleClickAction = () => {setClickedSportCars((clickedSportCars) => !clickedSportCars);setClickedElectricCars((clickedElectricCars) => !clickedElectricCars);};

Then in the useEffect there are 2 conditions:
If clickedSportCars is true, then set the corresponding state (the string) with the name of the css class for image input -> moveToLeft.
The same logic is applied for the boolean clickedElectricCars, but the css class is different -> moveFromRight.
(The two classes appear from an opposite direction)

useEffect(() => {if (clickedSportCars) {setsportListClassName("moveFromLeft");}if (clickedElectricCars) {setelecListClassName("moveFromRight");}}, [clickedSportCars, clickedElectricCars]);

don’t forget to enter the dependencies (states) of the useEffect in the array of dependencies in the second argument of this function.

And the result at this stage:

The Sport category is on the screen

As you can see, each image arrives with a slight delay of a few ms compared to the image that precedes it,
This is due to the delay implemented in the App.css file

.slider ul.moveToLeft li:first-child,.slider ul.moveFromRight li:first-child,.slider ul.moveToRight li:nth-child(4),.slider ul.moveFromLeft li:nth-child(4) {animation-delay: 0ms;}.slider ul.moveToLeft li:nth-child(2),.slider ul.moveFromRight li:nth-child(2),.slider ul.moveToRight li:nth-child(3),.slider ul.moveFromLeft li:nth-child(3) {animation-delay: 90ms;}.slider ul.moveToLeft li:nth-child(3),.slider ul.moveFromRight li:nth-child(3),.slider ul.moveToRight li:nth-child(2),.slider ul.moveFromLeft li:nth-child(2) {animation-delay: 180ms;}.slider ul.moveToLeft li:nth-child(4),.slider ul.moveFromRight li:nth-child(4),.slider ul.moveToRight li:first-child,.slider ul.moveFromLeft li:first-child {animation-delay: 270ms;}

Create navigation from one category to another…

I create a SliderNav.js file

Code explanation:

This component takes the props that we’ll implement in the Slider.js component right after.
The props are, the 2 boolean values for the sport and electric categories, then the handleClickAction function.
(all these props come from the custom hook implemented earlier).

Then a condition is implemented for each css class, if the boolean is true then put selected as class otherwise none.
And finally in this component, a function onClick={handleClickAction} for each span contained in the nav tags.

Then, make some change on Slider.js file:

I have added new import from the custom hook:

const {sportListClassName,elecListClassName,clickedSportCars,handleClickAction,clickedElectricCars,} = useSliderAminated();

I implemented the classes to be dynamic
for the ul with the id ListSport:

className={`badgesList  ${sportListClassName}`}

for the ul with the id ListElectric:

className={`badgesList ${elecListClassName}`}

And i have added SliderNav component with the necessary props:

import SliderNav from "./SliderNav";......<SliderNavclickedSportCars={clickedSportCars}handleClickAction={handleClickAction}clickedElectricCars={clickedElectricCars}/>

ok, let’s try this….

Ok, let’s see what’s appen!

Result:

the category navbar appears well, ok…
Clicking on each option works correctly… good,
entering my images on the screen works fine too, cool…
But… the output of the images is missing!

That’s what we will implement now.

Let’s go into the custom hook useSliderAnimated.js to add some code.

Modify the useEffect with this:

I added the moveToRight class to the electric car category (this is the code for the output of the image screen of this category).
And the same for the class moveToLeft in the opposite case.

Let’s see the result now:

It’s work… but!

Ok, everything works, but if you look carefully, you will notice that the input animation of the sport component and the output animation of the electric component are superposed.
We need to add a delay between each animation…
let’s go back to the useSliderAnimated.js file!

let’s modify the useEffect to do so.

What have I changed?

Let’s take the case of clickedSportCars:
when the boolean value of this one is true, then I give as class to the inverse component (setElecListClassName -> moveToRight) which animates the output of the screen of this section.
Then, after 500ms I set the class moveFromLeft to the sport section, which this time animates the entry of the section on the screen…

The logic is identical for the other boolean value but with moveToLeft to animate the output of the sport section, then 500ms later, I apply the class moveFromRight for electric section.

And the result:

it’s work as expected, cool!

As you can see, there is first the screen exit animation and then the screen entry animation 500ms later… all works as expected!

Last step, create the automatic animation!

What has changed?

const autoSlideTimer = setInterval(() => {handleClickAction();}, 3700);

I added autoSlideTime with a time interval of 3700 ms between each category change.

Important thing:

When an asyncronous task is processed in a useEffect, it is necessary to implement a cleanup function, like this:

return () => {clearInterval(autoSlideTimer);clearTimeout(setTimeout);};

Each time the component is unmounted the asynchronous tasks are destroyed, whether they are completed or not, it avoids memory leaks, that’s why it is necessary to do it.

And.. the final result:

tada…

That’s it, All works (automatic & on click) correctly, as expected.

The link to the repo of this tutorial:

I hope this article will be useful to you and save you from messing around with unnecessary npm packages.

Thanks for reading this tutorial.

See you soon for a new React js tutorial.

--

--