React 및 CSS로 애니메이션 카운터 만들기

이 블로그에서는 웹 전체에서 계속 찾는 애니메이션 카운터 구성 요소의 나만의 버전을 만들려고 합니다.

제가 어떻게 진행했는지 보여드리겠지만 피드백을 받고 싶습니다. 이 작업을 수행하는 더 좋은 방법을 알고 있습니까?

댓글을 남기거나 [email protected]로 이메일을 보내주세요.



the code on Github



지도 시간



목차


  • 예비 정크
  • 카운트 구성 요소
  • 증분 함수
  • 결론

  • 예비 정크



    나는 create-react-app 를 설정하고 기본 항목을 삭제했으며 파일 구조는 다음과 같습니다.



    앱 구성 요소에 기본 CSS(height , widthflex box )를 추가하여 모든 콘텐츠를 중앙에 배치했습니다.

    .App {
      width: 100%;
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
    }
    


    또한 Count 구성 요소에 매핑할 데이터가 포함된 JSON 파일을 설정했습니다.

    {
        "counts": [
            {
                "id": "001",
                "label": "A Really Big Number",
                "number": "900000",
                "duration": "2"
            },
            {
                "id": "002",
                "label": "Ice Cream Flavors",
                "number": "5321",
                "duration": "2"
            },
            {
                "id": "003",
                "label": "Customers Served",
                "number": "100",
                "duration": "2"
            },
            {
                "id": "004",
                "label": "Complaints",
                "number": "0",
                "duration": "2"
            }
        ]
    }
    


    카운트 구성 요소



    내 Count 구성 요소의 목적은 count가 실행되고 애니메이션을 렌더링하는 방법에 대한 일부 데이터를 수락하는 것입니다.

    먼저 기본 구성 요소를 설정합니다.

    import React from 'react';
    
    //styling
    import './Count.css';
    
    const Count = props => {
      // label of counter
      // number to increment to
      // duration of count in seconds
      const {label, number, duration } = props.data
    
      return (
        <div className="Count">
          <h3>
            <i>{label}: {number}</i>
          </h3>
        </div>
      );
    }
    
    export default Count;
    
    


    Count는 data.json에서 데이터 항목의 소품을 가져옵니다. 소품에서 label , numberduration 를 분해했습니다.

    JSX를 사용하여 labelnumber를 헤더로 반환합니다.

    나중에 애니메이션으로 변경number하지만 지금은 내가 만들고 있는 것의 하드 코딩된 버전의 스타일을 지정할 수 있습니다.

    .Count {
        padding: 2rem;
        margin: 1rem;
    
        border-radius: 2em;
        box-shadow: 1px 2px 2px #0D3B66;
        background-color: #FAF0CA;
    
        display: flex;
        align-items: center;
        justify-content: center;
    
        color: #0D3B66;
    }
    


    증분 함수



    다음 세 단계에서 0에서 원하는 숫자로 증가하는 함수를 설정했습니다.

    1) 디스플레이 번호를 저장하는 후크useState를 설정하고 업데이트되면 구성 요소의 렌더링을 트리거합니다.

    후크는 다음과 같습니다.

      // number displayed by component
      const [count, setCount] = useState("0");
    

    count 대신 number 를 표시하도록 JSX를 업데이트합니다.

      return (
        <div className="Count">
          <h3>
            <i>{label}: {count}</i>
          </h3>
        </div>
      );
    


    2) 카운트 및 증분 시간을 계산하는 후크useEffect를 설정합니다.
    useEffect()는 카운트를 처리할 익명 함수를 사용합니다. 변수 startend를 만듭니다. start는 0으로 설정됩니다.

    처음에는 number를 끝으로 사용했습니다. 그러나 많은 수의 경우 밤새도록 해야 합니다. 대신 숫자의 처음 세 자리만 늘리고 나머지는 숫자를 업데이트하기 전에 붙여넣습니다.

    지속 시간(초)을 계획된 증분 수로 나누어 각 증분 비율을 계산하고 밀리초로 변환하기 위해 1000을 곱합니다.
    게시물용 이미지

      useEffect(() => {
        let start = 0;
        // first three numbers from props
        const end = parseInt(number.substring(0,3))
        // if zero, return
        if (start === end) return;
    
        // find duration per increment
        let totalMilSecDur = parseInt(duration);
        let incrementTime = (totalMilSecDur / end) * 1000;
    
        // dependency array
      }, [number, duration]);
    


    I was hoping to speed up the interval to make up for how long it would take to increment large numbers, but setInterval() has a minimum duration of 10 milliseconds. Any number less than 10 will reset back to 10.



    3) 동일한 useEffect 후크에서 setInterval()를 사용하여 구성 요소를 다시 렌더링하는 부작용으로 개수를 늘립니다.

    하나를 추가하여 시작하고 setCount()를 호출하여 내 useState 후크를 업데이트합니다. start를 문자열로 변환하고 큰 숫자인 경우 이전에 잘라낸 나머지 숫자를 연결합니다.

        // timer increments start counter 
        // then updates count
        // ends if start reaches end
        let timer = setInterval(() => {
          start += 1;
          setCount(String(start) + number.substring(3))
          if (start === end) clearInterval(timer)       
        }, incrementTime);
    


    이제 전체 구성 요소가 다음과 같이 표시됩니다.

    import React, { useEffect, useState } from 'react';
    
    //styling
    import './Count.css';
    
    const Count = props => {
      // label of counter
      // number to increment to
      // duration of count in seconds
      const {label, number, duration } = props.data
    
      // number displayed by component
      const [count, setCount] = useState("0")
    
      useEffect(() => {
        let start = 0;
        // first three numbers from props
        const end = parseInt(number.substring(0,3))
        // if zero, return
        if (start === end) return;
    
        // find duration per increment
        let totalMilSecDur = parseInt(duration);
        let incrementTime = (totalMilSecDur / end) * 1000;
    
        // timer increments start counter 
        // then updates count
        // ends if start reaches end
        let timer = setInterval(() => {
          start += 1;
          setCount(String(start) + number.substring(3))
          if (start === end) clearInterval(timer)       
        }, incrementTime);
    
        // dependency array
      }, [number, duration]);
    
      return (
        <div className="Count">
          <h3>
            <i>{label}: {count}</i>
          </h3>
        </div>
      );
    }
    
    export default Count;
    


    결론



    나는 이런 종류의 애니메이션에 대한 여러 기사를 읽고 그들의 아이디어를 내 직감과 결합하여 이 추상적인 재사용 가능한 구성 요소를 만들었습니다.

    내가 생각한 것이 최선의 방법인지 잘 모르겠습니다. 예를 들어 setInterval에는 내가 예상하지 못한 한계가 있었습니다. 나는 약간의 피드백을 원합니다. 언제든지 댓글을 달거나 [email protected]로 이메일을 보내주세요.

    최고, 제이슨

    좋은 웹페이지 즐겨찾기