Search code examples
javascriptreactjsonclicklistener

React App, struggling to create an independent handleToggle


When I click on to open the image, activating a new class, it works, creating "active" on all pictures showing the last one in detail. I'm struggling to find a way to isolate and when the image is clicked only that image is showing in detail. It is following the code and the link to check the result of the problem.

Container.js

import React, { useState } from "react";
import "./Container.css";
import img1 from "./img/img1.jpg";
import img2 from "./img/img2.jpg";
import img3 from "./img/img3.jpg";
import img4 from "./img/img4.jpg";

function Container() {
  const [isActive, setActive] = useState("false");

  const handleToggle = () => {
    setActive(!isActive);
  };
  return (
    <div className="container">
      <div className="box">
        <div className={`imgBx ${isActive ? "" : "active"}`}>
          <img src={img1} alt="img1" onClick={handleToggle} />
        </div>
      </div>
      <div className="box">
        <div className={`imgBx ${isActive ? "" : "active"}`}>
          <img src={img2} alt="img2" onClick={handleToggle} />
        </div>
      </div>
      <div className="box">
        <div className={`imgBx ${isActive ? "" : "active"}`}>
          <img src={img3} alt="img3" onClick={handleToggle} />
        </div>
      </div>
      <div className="box">
        <div className={`imgBx ${isActive ? "" : "active"}`}>
          <img src={img4} alt="img4" onClick={handleToggle} />
        </div>
      </div>
    </div>
  );
}

export default Container;

Container.css

.container {
  position: absolute;
  display: flex;
  height: calc(100% - 200px);
  width: calc(100% - 200px);
  z-index: 100;
}
.container .box {
  position: relative;
  width: 25%;
  height: 100%;
  overflow: hidden;
  border-right: 10px solid #111;
}
.container .box:last-child {
  border-right: none;
}
.container .box .imgBx {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transition: 0.5s;
  opacity: 0.5;
  filter: grayscale(1);
  cursor: pointer;
}
.box .imgBx.active {
  position: fixed;
  top: 100px;
  left: 100px;
  height: calc(100% - 200px);
  width: calc(100% - 200px);
  z-index: 1000;
  opacity: 1;
  filter: grayscale(0);
}
.container .box .imgBx:hover {
  opacity: 1;
  filter: grayscale(0);
}
.container .box .imgBx img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

App.js

import Header from "./components/Header";
import Container from "./components/Container";
import Footer from "./components/Footer";

function App() {
  return (
    <section>
      <Header></Header>
      <Container></Container>
      <Footer></Footer>
    </section>
  );
}

export default App;

Solution

  • I think the error in this line below

    const [isActive, setActive] = useState("false"); // false is a string
    

    It should

    const [isActive, setActive] = useState(false); //boolean
    

    so when you are

    className={`imgBx ${isActive ? "" : "active"}`} 
    // it's finding isActive true, always as
    // string is always true
    

    And if you want to design your project so that each div has its own active status , you should,

    //data.js
    
    const data = [
       {
        image: './img/img1.jpg',
        status: false
    },
     {
        image: './img/img2.jpg',
        status: false
    }, {
        image: './img/img3.jpg',
        status: false
    }, {
        image: './img/img4.jpg',
        status: false
    },
    ]
    export defaut data;
    

    Then in your project

    import data from './data.js'
    
    function Container() {
      const [dataProj, setdata] = useState(data);
    
      
      return (
    <div className="container">
       {
        dataProj.map((item,index)=>(
      <div className="box" key={index+1}>
            <div className={`imgBx ${item.status? "" : "active"}`}>
              <img src={item.image} alt=`img${index+1}` onClick={()=>{
                let itemData = [...dataProj];
                let updatedItem = {...itemData[index],status:!item.status};
                itemData[index] = updatedItem;
                setdata(itemData);
    } />
            </div>
          </div>
    ))
    }
    </div>
        
      );
    }
    
    export default Container;
    

    This way you can set status for each image. I hope it works, Thanks