skip to Main Content

I am very new in react, and am trying to create a function that maps 5 cards on the screen from an array but is able to change the CSS of only the one that is clicked.

export default function Projects(){
    const [card, setCard] = useState("cardOn");

    const toggleCard =  (props) => {

        if(card === "cardOff"){
            setCard("cardOn");
            console.log("card is now on");
        }
        else{
            setCard("cardOff");
            console.log("card is now off");
        }
    }
    
    return(
        <div id = "projectsGridContainer">
            <div id = "projectsGrid">
                {projs.map(function(project){
                    return(
                        
                            <div id = "projectContainer" className = {card} onClick={toggleCard} >
                                <div className="projectImage">{project.image}</div>
                                <p id="projectTitle">{project.title}</p>
                                {/* <p>{project.description}</p> */}
                            </div>

                    );
                 })}
            </div>
        </div>
    )
}

The code works in changing the CSS of all the cards at once. Is there a way to make it so only the one clicked changes?

3

Answers


  1. Your two state values are "cardOn" and "cardOff". Given either of those values, which of your cards do you think is currently "clicked"?

    Store that information in state. For example, if your "projects" have an ID value then you can store that in state. Initially no card would be clicked:

    const [card, setCard] = useState();
    

    You can set the clicked card in the event handler:

    onClick={() => setCard(project.id)}
    

    And use that value to determine the class name:

    className={card === project.id ? "cardOn" : "cardOff"}
    
    Login or Signup to reply.
  2. One solution would be to make a Card an own component with it’s own state. Your code could look like this:

    function Card({project}) {
        const [card, setCard] = useState("cardOn");
    
        const toggleCard = () => {
            if (card === "cardOff") {
                setCard("cardOn");
                console.log("card is now on");
            } else {
                setCard("cardOff");
                console.log("card is now off");
            }
        };
        return (
            <div id="projectContainer" className={card} onClick={toggleCard}>
                <div className="projectImage">{project.image}</div>
                <p id="projectTitle">{project.title}</p>
                {/* <p>{project.description}</p> */}
            </div>
        );
    }
    
    export default function Projects() {
        return (
            <div id="projectsGridContainer">
                <div id="projectsGrid">
                    {projs.map((project, index) => (
                        <Card key={index} project={project} />
                    ))}
                </div>
            </div>
        );
    }
    

    As <Card key={index} project={project} /> gets an Object with the attributes key and project here under the hood, the curly braces around the parameter project in the definition of Card are important for destructuring. You could also use just props as parameter without curly braces and then in the function use props.project.

    The use of index as a key is just an example and considered bad practice as the Sonarlint rule (javascript:S6479) states. The reason is that the index can change. Better use a unique id, maybe your projects have such an attribute anyway.

    Login or Signup to reply.
  3. There are several ways you can achieve this one of which is to store the unique identifier of each project in your state and use it to check if a card is on or off ( this would usually be the id)

    
    import { useState } from 'react';
    
    export default function App() {
      const [card, setCard] = useState('');
    
      return (
        <div id='projectsGridContainer'>
          <div id='projectsGrid'>
            {projs.map(function (project) {
              return (
                <div
                  key={project.id}
                  id='projectContainer'
                  className={
                    card === project.id
                      ? '/* apply click specific classnames here */'
                      : '/* apply classname here */'
                  }
                  onClick={() => setCard(project.id)}
                >
                  <div className='projectImage'>{project.image}</div>
                  <p id='projectTitle'>{project.title}</p>
                  <p>{project.description}</p>
                </div>
              );
            })}
          </div>
        </div>
      );
    }
    
    

    Also do not forget to add a unique key prop to each item in your list

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search