How to set a css property (background-color) dynamically in React?

Viewed 4156

I have a slideshow based on an array of objects with its characteristics, one of them is the background-color of the current slide. I have a property called bg which stores it. This is what I am using to set each background-color, which changes to every image, however I am using an inline style to do that.

I'd like to know if there is a way to do that without using this inline style?

Here is a sample of my code:

import React from 'react'
import { Fragment } from 'react'

import classes from './MainPageHeader.module.css'

const MainPageHeader = props => {

    let [minorSlideImg, setMinorSlideImg] = React.useState(0)

    let minorSlides = [
        {
            img: require('../../../assets/images/Header/MinorSlider/imgSolo1-mainpage.png'),
            alt: 'Produto 1',
            linkText: ['PRODUTO 5', '$ 19.99'],
            productId: 5,
            bg: 'rgb(151, 105, 105)'
        },
        {
            img: require('../../../assets/images/Header/MinorSlider/imgSolo2-mainpage.png'),
            alt: 'Produto 2',
            linkText: ['PRODUTO 13', '$ 199.99'],
            productId: 13,
            bg: '#fad3e0'
        },
        {
            img: require('../../../assets/images/Header/MinorSlider/imgSolo3-mainpage.png'),
            alt: 'Produto 3',
            linkText: ['PRODUTO 10', '$ 499.99'],
            productId: 10,
            bg: '#ccc'
        },
        {
            img: require('../../../assets/images/Header/MinorSlider/imgSolo4-mainpage.png'),
            alt: 'Produto 4',
            linkText: ['PRODUTO 11', '$ 999.99'],
            productId: 11,
            bg: 'rgb(238, 225, 183)'
        },
    ]
    
    const passSlideHandler = () => {
        if (minorSlideImg < minorSlides.length - 1) {
            setMinorSlideImg(minorSlideImg + 1)
        } else {
            setMinorSlideImg(0)
        }
    }   
    
    React.useEffect(() => {
        const interval = setTimeout(() => {
            passSlideHandler()
        }, 5000);
        return () => clearTimeout(interval);
    });    


    return (
        <Fragment>
            <div 
                className={classes.MinorSlider_subContainer} 
                style={{backgroundColor: minorSlides[minorSlideImg].bg}} // <= This is what I'd like to remove
            >
                <img 
                    src={minorSlides[minorSlideImg].img}
                    alt={"img-1"} 
                />
            </div>
        </Fragment>
    )
}

export default MainPageHeader

CSS:

.MinorSlider_subContainer {
    height: 65%;
    width: 50%;
    background-color: #ccc;
}

.MinorSlider_subContainer img {
    max-width: 100%;
}

.MinorSlider_subContainer div {
    position: relative;
    background-color: white;
    width: 100%;
    height: 65px;
}

.MinorSlider_subContainer div > *{
    display: flex;
    flex-direction: column;
    justify-content: space-evenly;

    width: 100%;
    height: 100%;
    padding-left: 25px;
    text-decoration: none;
}

.MinorSlider_subContainer div p {
    margin: 0;
    color: rgb(75, 75, 75);
}

As can be seen, every five seconds the index of minorSlides changes, therefore, the slide that is being shown changes as well. This index is used to refer to each feature of the current slide.

So, is there a way to remove this inline style and make my JSX cleaner?

If I was using HTML, CSS and JS I could do that with JQuery or even plain JS, but I don't know how to do that here. I know I could create the element with a loop, but I'd like to keep changing only the index and not the whole element.

Here is the sildeshow:

enter image description here

3 Answers

If you can't create a css class for every color, the other option is to add the style tag and override the background-color property:

const subcontainerBackground = `.${classes.MinorSlider_subContainer} { background-color: ${minorSlides[minorSlideImg].bg}}`
        
return {(
   <Fragment>
      <style>
        {subcontainerBackground}
      </style>
      <div className={classes.MinorSlider_subContainer} >
         //....
      </div>
    </Fragment>
}

EDIT

Also you can add the style tag using Document.createElement():

  useEffect(() => {
    const content = `.${classes.MinorSlider_subContainer} { background-color: ${minorSlides[minorSlideImg].bg}}`;
    const style = document.createElement("style");
    style.innerHTML = content;
    document.head.appendChild(style);

    return () => document.head.removeChild(style);
  }, [minorSlideImg]);

Well it should be alright to use inline styling in this case.

Additionally you can do something like:

{
  ...
  bgClass: 'red'
}

add that class to the div element:

<div className={`classes.MinorSlider_subContainer ${minorSlides[minorSlideImg].bgClass}`} />

and style it in the end:

.red {
  background: 'red';
}

Or you can try to use reference

const ref = useRef()

useEffect(() => {
  if (ref.current == null) {
    return
  }

  ref.current.style.backgroundColor = minorSlides[minorSlideImg].bg
}, [minorSlideImg, ref])

<div ref={ref} />

Here is my solutions for the same. Except, I add the colours in a list and use the rand function.

Here is the colour list

 const color_list = [
    "tomato",
    "blueviolet",
    "cornflowerblue",
    "indianred",
    "MediumAquaMarine",
    "MediumPurple",
    "Rebeccapurple",
    "sandybrown",
    "seagreen",
    "palevioletred",
    "lightsteelblue",
    "Gold",
    "teal",
  ];

I create a variable and add random function to it, to select a bunch of colours.

const rando_color = color_list[Math.floor(Math.random() * color_list.length)];

Simply pass the variable in the style option in the html div tag to dynamically assign background color

<div
   p={4}
   style={{
   backgroundColor: rando_color, // Added variable here 
   fontFamily: "Oswald",
   border: "solid 2px white",
   }}
   >
<h1>Some Content</h1>
  </div>

To make it simple, just add the variable directly in the tag without any curly braces. Also you could try using this variable in a react state for better loading. Add a default prop as well.

Related