DEV Community

Amber M Webb
Amber M Webb

Posted on

How I modernized an old React carousel app with hooks and styled-components

I am a front end developer. I have been writing front end applications since long before it was called front end. I do not remember how I was adding color and font weight to my HTML back in 2002. I also do not remember when I started using CSS but I do recall my first coding job where I came to hate it. There was no hot reloading back then, so any change that was made to the CSS I had to refresh the browser to see it. Then of course, I had to look in ALL THE BROWSERS (do not get me started on Internet Explorer 7) to make sure the interface looked like it was supposed to. I have had a few colleagues ask me the past few years how I felt about styled components. I had no answer for them except that I hate CSS and I want to go the easiest route to accomplish this necessary evil. I had no desire to learn styled components and would stick to class based styling or CSS modules thank you very much. One of the very best things about using frameworks like Bootstrap or Material UI is that the components are already styled out of the box. Sure yeah, you can customize the styling but you can also just plug them in, pass in your props and focus more on the UI interactions, the architecture and the performance of your application. You know, the stuff that makes coding so much fun.

I recently revisited a little React carousel application that I had built a couple of years ago. It had been sitting in my Github getting very stale and needed quite a bit of freshening up. It was using a much older version of React with class components. I have been riding the React hooks bandwagon for over a year, so it was time to convert it over. It felt awesome to pull out the constructors and lifecycle methods and replace with useState and useEffect hooks.

Here is my original CarouselItem component using class component method:

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import './Carousel.css'

class CarouselItem extends Component {
  static propTypes = {
    activeIndex: PropTypes.number.isRequired,
    index: PropTypes.number.isRequired,
    item: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)
    this.state = {
      className: props.index === props.activeIndex ? 'active' : ''
    }
  }

  componentWillReceiveProps (nextProps) {
    const {
      index
    } = this.props

    if (index === nextProps.activeIndex) {
      this.setState({className: 'active'})
    } else {
      this.setState({className: ''})
    }
  }

  render () {
    const { item } = this.props
    const { className } = this.state

    return (
      <li className={`Carousel-item ${className}`}>
        {item}
      </li>
    )
  }
}

export default CarouselItem

Here is my CarouselItem component after updating it to use hooks:

import React, { useEffect, useState } from 'react';
import './Carousel.css';

export default function CarouselItem(props) {
  const { index, activeIndex, item } = props;
  const [className, setClassName] = useState(props.index === props.activeIndex ? 'active' : '');

  useEffect(() => {
    if (index === activeIndex) {
      setClassName('active');
    } else {
      setClassName('');
    }
  }, [index, activeIndex]);

  return (
    <li className={`Carousel-item ${className}`}>
      {item}
    </li>
  );
}

It was looking more modern already! But something was still not quite right. The ugly class names in my elements were bringing it down. Now, the styles are central to the way the carousel behaves. The active images have diplay:block style and fade in to view and the little navigation controls change color when its respective image is active. I was setting the active class name in state in the useEffect hook. I decided it was time to give styled components a go.

Styled components are very easy to use. Run this in your terminal:

npm install --save styled-components

Add this to your React component:

import styled from 'styled-components'

Create a styled element like so:

const MyAwesomStyledComponent = styled.div`
  background: red;
`

Add it like this:

<MyAwesomStyledComponent />

That is what I did! It felt great to delete the stylesheets. There was also an added benefit that was both surprising and delightful. Take a quick look again at my React hooks version of CarouselItem up above and then take a look at CarouselItem with styled components:

import React from 'react';
import styled, {keyframes} from 'styled-components';
import { CarouselItemInterface } from "./types";

const fadeIn = keyframes`
  from {
      opacity: 0;
  }
  to {
      opacity: 1;
  }
`;

const Item = styled.li`
  display: ${(props: CarouselItemInterface) => props.index === props.activeIndex ? 'block' : 'none'};
  animation: ${fadeIn} 2s;
  -moz-animation: ${fadeIn} 2s;
  -webkit-animation: ${fadeIn} 2s;
  -o-animation: ${fadeIn} 2s;
`;

export default function CarouselItem(props: CarouselItemInterface) {
  return (
    <Item {...props}>
      {props.item}
    </Item>
  );
}

Since props are passed into the styled component, I can do my conditional checking for display: block or display: none directly in it! I was able to remove both the useState and useEffect hooks for a much more streamlined component!

My new thoughts on CSS - it is awesome with styled components. My examples are pretty basic and there is much more to learn and use with them. I look forward to creating new projects, and maybe even converting some of my older existing projects, to use styled components.

Do yourself a favor and check it out : https://styled-components.com/

Top comments (0)