Ad

Using Animations On Components With Render

I want to run an animation using transition. The problem is I am using state to control it. So now, the components are created in render method. But every time the state is changed, the component is re-rendered. So how can I create the smaller components, so they are in scope, and I can use state to animate them?

import React, {Component, Fragment} from 'react';
import ArrowTemplate from "./ArrowTemplate";
import styled from 'styled-components';

class Accordion extends Component {
    constructor(props) {
        super(props);
        this.state = {isAccordionExpanded: false};
        this.toggleAccordion = this.toggleAccordion.bind(this);
    }

    toggleAccordion() {
        this.setState({isAccordionExpanded: !this.state.isAccordionExpanded})
    }

    render() {
        const {isAccordionExpanded} = this.state;
        const AccordionSection = styled.div`
            display: flex;
            flex-direction: column;
`;
        const AccordionBtn = styled.button`
            background-color: #eee;
            color: #444;
            cursor: pointer;
            padding: 18px;
            display: flex;
            align-items: center;
            border: none;
            outline: none;
            transition: background-color 0.6s ease;
            :hover,
            :focus,
            :active {
              background-color: #ccc;
            }
`;
        const P = styled.p`
            font-family: "Open Sans", sans-serif;
            font-weight: 600;
            font-size: 14px;
`;
        const AccordionContent = styled.div`
            background-color: white;
            ${isAccordionExpanded === true ? `height: 100px` : `height: 0`};
            overflow: hidden;
            transition: max-height 0.6s ease;
`;
        const AccordionText = styled.div`
            font-family: "Open Sans", sans-serif;
            font-weight: 400;
            font-size: 14px;
            padding: 18px;
`;
        return (
            <AccordionSection>
                <AccordionBtn
                    onClick={this.toggleAccordion}
                >
                    <P>
                        <ArrowTemplate
                            color={"black"}
                            direction={"down"}
                            aria={"aria-roles: 'button'"}
                            onClick={this.toggleAccordion}
                        />
                    </P>
                </AccordionBtn>
                <AccordionContent>
                    <AccordionText>
                        test
                    </AccordionText>
                </AccordionContent>
            </AccordionSection>
        )
    }
}

export default Accordion;

ArrowTemplate

import React from "react";
import BlackDownArrowSVG from './svgs/black-down-arrow.svg';
import WhiteDownArrowSVG from './svgs/white-down-arrow.svg';
import styled from 'styled-components';
import PropTypes from 'prop-types';

ArrowTemplate.propTypes = {
    color: PropTypes.string.isRequired,
    direction: PropTypes.string.isRequired,
    styles: PropTypes.string,
    aria: PropTypes.string.isRequired,
    onClick: PropTypes.func.isRequired,
};

function ArrowTemplate(props) {
    const {color, direction, styles, aria, onClick} = props;
    const StyledArrowTemplate = styled.img.attrs({
        src: color.toLowerCase() === "black" ? BlackDownArrowSVG : WhiteDownArrowSVG,
        aria,
    })`
            ${direction.toLowerCase() === "up" ? "transform: rotate(180deg);" : ""}
            ${styles}
    `;
    return <StyledArrowTemplate onClick={onClick}/>;
}

export default ArrowTemplate;
Ad

Answer

I managed to do this by passing the properties (state) to a styled component like so:

<AccordionContent
  ref={content}
  isAccordionExpanded={isAccordionExpanded}
  height={content.current === null ? '0' : content.current.scrollHeight}
>

const AccordionContent = styled.div`
      max-height: ${({ isAccordionExpanded, height }) => (isAccordionExpanded ? height : '0')}px;
      background-color: red;
      overflow: hidden;
      transition: max-height 0.7s;
  `;
Ad
source: stackoverflow.com
Ad