DEV Community

loading...

How to use an array of colors to change the button background color on the button press using one handleChange (Hooks)

harukakato35 profile image Haruka Kato ・3 min read

Screen Shot 2021-02-27 at 10.34.52
I have 6 buttons and I wanted to change the color once pressed separately.

At first, I decided to give useState to each button like this.

    const [color,setColor]=useState('#F5F5F5');
    const [textColor,setTextColor]=useState('black');
    const [color1,setColor1]=useState('#F5F5F5');
    const [textColor1,setTextColor1]=useState('black');
    const [color2,setColor2]=useState('#F5F5F5');
    const [textColor2,setTextColor2]=useState('black');
    const [color3,setColor3]=useState('#F5F5F5');
    const [textColor3,setTextColor3]=useState('black');


    const button = (
        <Button style={{background:color,color:textColor}}
                className={classes.paper}
                onClick={()=>{setColor("purple");setTextColor('white')
                }}>
            asda
        </Button>
    )

    const button1 = (
        <Button style={{background:color1,color:textColor1}}
                className={classes.paper}
                onClick={()=>{setColor1("purple");setTextColor1('white')
                }}>
            asda
        </Button>
    );


    const button2 = (
        <Button style={{background:color2,color:textColor2}}
                className={classes.paper}
                onClick={()=>{setColor2("purple");setTextColor2('white')
                }}>
            asda
        </Button>
    );

Enter fullscreen mode Exit fullscreen mode

But then I thought if there is a way to use less useState, and I decided to use one useState instead of using 12 useState in total.

I saw a lot of articles writing about updating multiple properties using one useState. But I did not see any article talking about updating the property by using an index.

First, you want to create an array of color using one useState. White is the initial color of the buttons.

   const [colors, setColors] = React.useState([
        "white",
        "white",
        "white",
        "white",
        "white",
        "white"
    ]);
Enter fullscreen mode Exit fullscreen mode

Then, you should create a function that has two arguments, index and value. I also had difficulties finding articles handleChange having two arguments.
You can create a new object(newColors this time) to overwrite the existing values.

    const handleChange = (index, value) => {
        const newColors = [...colors];
        newColors[index] = value;
        setColors(newColors);
    };
Enter fullscreen mode Exit fullscreen mode
newColors[index] = value;
Enter fullscreen mode Exit fullscreen mode

This means the new colors will be passed to colors(The array we created before).
For example, colors[0] = "purple".
Finally, you pass the updated color to SetColors.

                    <Button
                        style={{ background: colors[0] }}
                        className={classes.paper}
                        onClick={() => handleChange(0, 'purple')}>
                        asda
                    </Button>
Enter fullscreen mode Exit fullscreen mode

JSX will be like this. You want to specify the index of colors in style, and update the color using handleChange.

I have to tell you another thing here. I used onChange first to call handleChange and the background color didn't change. I found out that onChange doesn't work for some browsers, and you should use onClick.

It took me a week to solve this problem and hope this is helpful for you.

import React, {useState} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Link } from 'react-router-dom'
import Header from '../BasicComponents/Header';
import Footer from '../BasicComponents/Footer';
import Box from '@material-ui/core/Box';
import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';


const useStyles = makeStyles((theme) => ({
    root: {
        flexGrow: 1,
    },
    box:{
        position: 'relative',
    },
    button:{
        display: 'block',
        margin: '0 auto',
        marginBottom: 50,
        opacity: 0.7,
        height: 60,
        borderRadius: 50,
    },
    font:{
        textAlign: 'center',
    },
    paper: {
        textAlign: 'center',
        height: 100,
        margin:5,
        width: '100%',
        opacity: 0.7,
    },
    grid:{
        marginTop: 50,
        justifyContent: 'center',
        alignContent:  'center',
    },
    grid1:{
        justifyContent: 'center',
        alignContent:  'center',
        marginBottom: 50,
    },
}));

export default function Question2() {
    const classes = useStyles();

    const [colors, setColors] = React.useState([
        "white",
        "white",
        "white",
        "white",
        "white",
        "white"
    ]);
    const handleChange = (index, value) => {
        const newColors = [...colors];
        newColors[index] = value;
        setColors(newColors);
    };


    const grid = (
        <div>
            <Grid container className={classes.grid} >
                <Grid item xs={6} sm={2} >
                    <Button
                        style={{ background: colors[0] }}
                        className={classes.paper}
                        onClick={() => handleChange(0, 'purple')}>
                        asda
                    </Button>
                </Grid>
                <Grid item xs={6} sm={2}>
                    <Button
                        style={{ background: colors[1] }}
                        className={classes.paper}
                        onClick={() => handleChange(1, 'purple')}>
                        asda
                    </Button>
                </Grid>
                <Grid item xs={6} sm={2}>
                    <Button
                        style={{ background: colors[2] }}
                        className={classes.paper}
                        onClick={() => handleChange(2, 'purple')}>
                        asda
                    </Button>
                </Grid>
            </Grid>
            <Grid container className={classes.grid1}>
                <Grid item xs={6} sm={2}>
                    <Button
                        style={{ background: colors[3] }}
                        className={classes.paper}
                        onClick={() => handleChange(3, 'purple')}>
                        asda
                    </Button>
                </Grid>
                <Grid item xs={6} sm={2}>
                    <Button
                        style={{ background: colors[4] }}
                        className={classes.paper}
                        onClick={() => handleChange(4, 'purple')}>
                        asda
                    </Button>
                </Grid>
                <Grid item xs={6} sm={2}>
                    <Button
                        style={{ background: colors[5] }}
                        className={classes.paper}
                        onClick={() => handleChange(5, 'purple')}>
                        asda
                    </Button>
                </Grid>
            </Grid>
        </div>
    )

    return (
        <React.Fragment>
            <Header/>
            <Box
                className={classes.box}
                style={{
                    color: "#white"
                }}>
                <h2 className={classes.font}>Your customized stress release plan.</h2>
                <p className={classes.font}>100% complete</p>
                <h1 className={classes.font} >How did your stress change over the month?</h1>
                <h3 className={classes.font}>Select all that apply(required)</h3>
                {grid}
                <Button variant="contained" color="primary" disableElevation className={classes.button}>
                    <Link to="/result">⇨ Go to next question</Link>
                </Button>
            </Box>
            <Footer/>
        </React.Fragment>
    );
}
Enter fullscreen mode Exit fullscreen mode

Discussion (0)

pic
Editor guide