1
votes

I have a parent div ImgClust1 that onClick I want styled-components inside of it to change some styling based on state. Basically, as of current structure, on hover the TopLine, RightLine, LeftLine, and BotLine components transform and essentially display. I am looking for a way to use state so that onClick, those components height/width styles depending on the component adjust based on the state. The main home component structure is below:

Home.js:

import React, { useState } from 'react';
import Container from './Container';
import Box1 from './boxes/Box1';
import ImgClust1 from './imgClust/ImgClust1';
import TopLine from './imgHovers/TopLine';
import BotLine from './imgHovers/BotLine';
import LeftLine from './imgHovers/LeftLine';
import RightLine from './imgHovers/RightLine';

const Home = () => {

    const [fill, setFill] = useState(false);

return (
    <Container>
      <ImgClust1 onClick={() => setFill(!fill)}>
        <Box1>
            <img src= {img}/>
        <TopLine />
        <RightLine />
        <LeftLine />
        <BotLine />
         </Box1>
          </ImgClust1>
        </Container>
       )
}

export default Home;

ImgClust1.js:

import styled from 'styled-components';

const ImgClust1 = styled.div`
    display: inline-block;
    width: 41.667vw;
    top: 16.667vw;
    position: relative;
`;

export default ImgClust1;

Box1.js

import styled from 'styled-components';

const Box1 = styled.div`
   position: relative;
   height: auto;
   cursor: pointer;
   transition: 0.4s ease-in;
   overflow: hidden;
   display: block;
   width: inherit;
   :hover img {
      transform: matrix(1.1, 0, 0, 1.1, 0, 0);
   }
   :hover {
      z-index: 100 !important;
   }
   :hover div:nth-child(2) {
      transform: matrix(1,0,0,1,0,0);
      height: 30px;
   }
   :hover div:nth-child(3) {
      transform: matrix(1,0,0,1,0,0);
      width: 30px;
   }
   :hover div:nth-child(4) {
      transform: matrix(1,0,0,1,0,0);
      width: 30px;
   }
   :hover div:nth-child(5) {
      transform: matrix(1,0,0,1,0,0);
      height: 30px;
   }
   & img {
      position: relative;
      display: inline-block;
      width: 100%;
      height: auto;  
      z-index: -10;
      transition: 0.35s ease-in-out;
      transform: matrix(1, 0, 0, 1, 0, 0);
      :hover {
         transform: matrix(1.1, 0, 0, 1.1, 0, 0);
      }
    }
`;

export default Box1;

TopLines.js

import styled from 'styled-components';
import fill from '../Home';

const TopLine = styled.div`
    display: block;
    position: absolute;
    background-color: red;
    transition: 0.35s ease-in;
    transform: matrix(1,0,0,0,0,0);
    top: 0;
    transform-origin: top;
    left: 0;
    margin-top: -1px;
    width: 100%;
    height: ${fill ? '100%' : '1px'};
`;

export default TopLine;

I thought that my useState method would achieve the desired result I was looking for, but nothing happens onClick right now. I'm not sure if my state is the problem because of the way the styled components are nested, or if it has to do with syntax in the TopLine component where I'm looking to achieve the style change. Any help is greatly appreciated! For context, I'm going for a click animation on any of the images like this site: https://www.fabianfallend.com/ so essentially I have hover like it right now, but am looking for the correct method to initiate the onClick animation so that not only the div clicked gets filled, but the other divs get filled on the page as well.

1
Your ImgClust1 is not a Component. So it's not the useState function - Ryan Nghiem
@RyanNghiem what do you mean by this? - yaboy618
The problem is with how you are trying to use the state. This line: import fill from '../Home'; inside TopLines.js expects that you default exported a variable (that has nothing to do with the component state) inside Home. - Hamza El Aoutar
thank you i'm just now realizing this! this was super helpful - yaboy618

1 Answers

1
votes

You need to pass the state down to your styled components:

<ImgClust1 onClick={() => setFill(!fill)}>
  ...
  <TopLine fill={fill} />
  <RightLine fill={fill} />
  ...
</ImgClust1>

Then fill will be available as props to the styled component and it can be used like this:

const TopLine = styled.div`
  ...
  height: ${p => p.fill ? '100%' : '1px'};
`;

or:

const Box1 = styled.div`
  ...
  ${(p) =>
    p.fill
      ? " "
      : `
      :hover img {
        transform: matrix(1.1, 0, 0, 1.1, 0, 0);
      }
   `}
`;

Adapting styled components based on props