Reynald Lamury
Reynald Lamury

Reputation: 367

CSS Transition not working with react and styled components

I have a problem with css transition, i use styled component and the element add its className based on the changing of react useState which is triggered by onClick back and forth,

here is the part of the code that dont work as expected:

export const SearchProduct = ({ product }) => {
  const [descStatus, setdescStatus] = useState(false);

  const handleDesc = () => {
    setdescStatus(!descStatus);
  };

  return (
    <li>
      <Item>
        <Photo>
          <img src={`${product.productImg}`} alt={product.productTitle}></img>
        </Photo>
        <Information>
          <h3> {product.productTitle} </h3>
          <Desclook>
            <div className={descStatus ? 'active' : null} onClick={handleDesc}>
              {descStatus ? 'Close' : 'See Desc ...'}
            </div>
          </Desclook>
          {descStatus && (
            <Description --> this is part that dont work 
              className={descStatus ? 'showContent content' : 'content'}
            >
              {product.productDesc}
            </Description>
          )}

Here is the styled components part :

const Description = styled.p`
  margin: 10px;
  padding: 0;
  transition: all 0.3s ease-in-out;

  &.content {
    height: 0;
    overflow: hidden;
  }

  &.showContent {
    height: 70px;
    overflow-y: scroll;
  }
`;

Does anybody have any idea what happened with my code here cause i'm kinda new to react and styled component

Upvotes: 1

Views: 5711

Answers (2)

Mike Ryczkowski
Mike Ryczkowski

Reputation: 56

Remove the check for descStatus and always render <Description> instead. So instead of this:

{descStatus && (
  <Description
    className={descStatus ? 'showContent content' : 'content'}
  >
    {product.productDesc}
  </Description>
)}

Do this:

<Description
  className={descStatus ? 'showContent content' : 'content'}
>
  {product.productDesc}
</Description>

The reason behind this is a CSS transition needs to transition from a different value than the current value. In your code when you check if descStatus is true before rendering, your Description component will never have the className="content" and will always be rendered initially with a height of 70px, so no transition will occur.

Upvotes: 3

Aadarsh
Aadarsh

Reputation: 41

Hey you can solve it easily if you send the state as a prop instead of setting className And you should update the state based on previous state and as useState setter sets the state asynchronously you might need asynchronous version of setState this is irrelevant for this problem but can cause problems in some cases

const handleDesc = () => {
    setdescStatus(p => !p);
  };

For the styled component part

<Description --> this is part that dont work 
  show={descStatus}
  >
  {product.productDesc}
</Description>

and inside the styled component you can handle it like

import styled,{css} from 'styled-components';

const Description = styled.p`
  margin: 10px;
  padding: 0;
  transition: all 0.3s ease-in-out;

  //content class styles applied by default
  height: 0;
  overflow: hidden;

  //these styles will be applied only if show is true (css you can import from 
  //styled component as a named import)

  ${({show}) => show && css`
   height: 70px;
   overflow-y: scroll;
  `}
`;

Upvotes: 1

Related Questions