ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 13. Styled-components : 트랜지션 구현하기 - 컴포넌트 스타일링 | 벨로퍼트
    Front-end/React.js 2020. 7. 21. 15:18
    반응형

     

    이제 Dialog 의 기능은 모두 구현을 해주었습니다. 이번에는 Dialog 가 나타나거나 사라질 때 트랜지션 효과를 적용해보겠습니다. 트랜지션 효과를 적용 할 때에는 CSS Keyframe 을 사용하며, styled-components 에서 이를 사용 할 때에는 keyframes 라는 유틸을 사용합니다.

     

    Dialog가 나타날 때 DarkBackground 쪽에는 서서히 나타나는 fadeIn 효과를 주고, DialogBlock 에는 아래에서부터 위로 올라오는 효과를 보여주는 slideUp 효과를 줘보겠습니다. 애니메이션의 이름은 여러분들이 마음대로 지정 할 수 있습니다.

    /src/components/Dialog.js :

    import React from 'react';
    import styled, { keyframes } from 'styled-components';
    import Button from './Button';
    
    const fadeIn = keyframes`
      from {
        opacity: 0
      }
      to {
        opacity: 1
      }
    `;
    
    const slideUp = keyframes`
      from {
        transform: translateY(200px);
      }
      to {
        transform: translateY(0px);
      }
    `;
    
    const DarkBackground = styled.div`
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background: rgba(0, 0, 0, 0.8);
    
      animation-duration: 0.25s;
      animation-timing-function: ease-out;
      animation-name: ${fadeIn};
      animation-fill-mode: forwards;
    `;
    
    const DialogBlock = styled.div`
      width: 320px;
      padding: 1.5rem;
      background: white;
      border-radius: 2px;
      h3 {
        margin: 0;
        font-size: 1.5rem;
      }
      p {
        font-size: 1.125rem;
      }
    
      animation-duration: 0.25s;
      animation-timing-function: ease-out;
      animation-name: ${slideUp};
      animation-fill-mode: forwards;
    `;
    
    // ...

    이렇게 하면 컴포넌트가 나타날 때 트랜지션 효과가 나타날 것입니다. 이제 사라지는 트랜지션 효과도 만들어볼건데요, 이는 구현하기 조금 까다롭지만, 원리만 알면 굉장히 쉽습니다.

     

    사라지는 효과를 구현하려면 Dialog 컴포넌트에서 두개의 로컬 상태를 관리해주어야 합니다. 하나는 현재 트랜지션 효과를 보여주고 있는 중이라는 상태를 의미하는 animate, 나머지 하나는 실제로 컴포넌트가 사라지는 시점을 지연시키기 위한 localVisible 값입니다.

     

    그리고 useEffect 를 하나 작성해주어야 하는데요, visible 값이 true 에서 false 로 바뀌는 시점을 감지하여 animate 값을 true 로 바꿔주고 setTimeout 함수를 사용하여 250ms 이후 false로 바꾸어 주어야 합니다.

     

    추가적으로, !visible 조건에서 null 를 반환하는 대신에 !animate && !localVisible 조건에서 null 을 반환하도록 수정해주어야 합니다.

    /src/components/Dialog.js :

    import React, { useState, useEffect } from 'react';
    // ...
    
    function Dialog({
      title,
      children,
      confirmText,
      cancelText,
      onConfirm,
      onCancel,
      visible
    }) {
      const [animate, setAnimate] = useState(false);
      const [localVisible, setLocalVisible] = useState(visible);
    
      useEffect(() => {
        // visible 값이 true -> false 가 되는 것을 감지
        if (localVisible && !visible) {
          setAnimate(true);
          setTimeout(() => setAnimate(false), 250);
        }
        setLocalVisible(visible);
      }, [localVisible, visible]);
    
      if (!animate && !localVisible) return null;
      return (
        <DarkBackground>
          <DialogBlock>
            <h3>{title}</h3>
            <p>{children}</p>
            <ButtonGroup>
              <ShortMarginButton color="gray" onClick={onCancel}>
                {cancelText}
              </ShortMarginButton>
              <ShortMarginButton color="pink" onClick={onConfirm}>
                {confirmText}
              </ShortMarginButton>
            </ButtonGroup>
          </DialogBlock>
        </DarkBackground>
      );
    }
    
    // ...

    이제 확인 / 취소를 눌렀을 때 약간의 딜레이 이후에 Dialog 가 사라지는 것을 확인해보세요. 만약에 잘 모르겠다면 기존에 setTimeout 에서 250 으로 설정했던 것을 1000 으로 설정을 해보세요 (확인했다면 다시 250으로 되돌려놓으세요).

     

    이제 DarkBackground 와 DialogBlock 에 disappear 라는 props 를 주어서 사라지는 효과가 나타나도록 설정을 해보겠습니다.

     

    각 컴포넌트의 disappear 값은 !visible 로 해주시면 됩니다.

    /src/components/Dialog.js :

    import styled, { keyframes, css } from 'styled-components';
    // ...
    
    const fadeOut = keyframes`
      from {
        opacity: 1
      }
      to {
        opacity: 0
      }
    `;
    
    const slideDown = keyframes`
      from {
        transform: translateY(0px);
      }
      to {
        transform: translateY(200px);
      }
    `;
    
    const DarkBackground = styled.div`
      // ...
    
      ${props =>
        props.disappear &&
        css`
          animation-name: ${fadeOut};
        `}
    `;
    
    const DialogBlock = styled.div`
      // ...
    
      ${props =>
        props.disappear &&
        css`
          animation-name: ${slideDown};
        `}
    `;
    
    function Dialog({ ... }) {
      // ...
      
      return (
        <DarkBackground disappear={!visible}>
          <DialogBlock disappear={!visible}>
            // ...
          </DialogBlock>
        </DarkBackground>
      );
    }
    반응형

    댓글

Luster Sun