실전 프로젝트 - 7

박경준·2021년 8월 19일
0

재렌더링 최소화

스탑워치가 1초씩 변경될때마다 재렌더링 되면서 다른 요소들에 영향을 끼치는 문제 -> 페이지 동작에는 문제가 없지만, 재렌더링 발생과 액션이 계속 발생하는것이 마음에 들지 않았음...
WorkOut.js 내에서 스탑워치 시간 부분만 StopWatchCont 컴포넌트로 빼서 해당 컴포넌트만 재렌더링 되게 구성. 즉, 부모 컴포넌트는 스탑워치의 setInterval에 의해서 재렌더링 되는 문제가 사라졌다.
이전 글에서 기술했던 WorkOut 컴포넌트가 unmount 될때와 스탑워치 시간이 재계산될때마다 두 상황에서 렌더링 문제를 해결함으로써 WorkOut 페이지에서 불필요한 렌더링을 모두 정리했다.
WorkOut 페이지는 특히나 재렌더링이 많았고 (useState 때문에 초당 재렌더링이 됐었음.) 그런 페이지를 렌더링 정리했다는 점에서 더욱 의의가 있었다.

// StopWatchCont.js

import React, { useState, useRef, useEffect } from 'react';
import { Text } from '../shared/Styles';

const StopWatchCont = ({ timeStop, setResultTime }) => {
  const timeRef = useRef(0);
  const [time, setTime] = useState(0);
  const timerId = useRef(null);
  // 스톱워치
  useEffect(() => {
    timerId.current = setInterval(() => {
      if (!timeStop) {
        timeRef.current += 1;
        setTime(timeRef.current);
      } else {
        clearInterval(timerId.current);
        setResultTime(timeRef.current);
      }
    }, 1000);
    return () => {
      clearInterval(timerId.current);
      setResultTime(timeRef.current);
    };
  }, [time.current, timeStop]);

  return timeStop ? (
    <Text
      type="contents"
      color="#9e9ea0"
      fontSize="60px"
      fontWeight="bold"
      margin="0"
    >
      {parseInt(time / 60) < 10
        ? `0${parseInt(time / 60)}`
        : parseInt(time / 60)}
      :{time % 60 < 10 ? `0${time % 60}` : time % 60}
    </Text>
  ) : (
    <Text
      type="contents"
      color="#B4AFFF"
      fontSize="60px"
      fontWeight="bold"
      margin="0"
    >
      {parseInt(time / 60) < 10
        ? `0${parseInt(time / 60)}`
        : parseInt(time / 60)}
      :{time % 60 < 10 ? `0${time % 60}` : time % 60}
    </Text>
  );
};

export default StopWatchCont;

캘린더 직접 만들기

보통의 회사에서는 달력 정도는 라이브러리를 사용하지 않고 직접 만들어 사용한다는 말을 듣고, 도전과제 느낌으로 직접 만들어보았다. 우선 달력을 만들기 위해서는 moment 라이브러리를 활용해야하는데 제공하는 메서드를 확인해야했다. (startOf, clone, week 등등...)
라이브러리를 사용하지 않고 내 코드로 구성하니, 확실히 onClick 같은 이벤트를 원하는 곳에 추가하고, 요소를 재구성하기가 쉬웠다. (라이브러리를 썼다면 api 문서를 읽어보느라 추가적인 시간이 들어갔을것이고, 그 이전에 내가 원하는 기능을 제공해주는 라이브러리인지 확인도 필요했을 것이다.)
캘린더 구성 순서는 아래 코드 확인.

// Calendar.js

// 이번달의 시작 주, 끝 주를 구함.
const start_week = moment(today).startOf('month').week();
const end_week = moment(today).endOf('month').week();

// 달력에 넣을 주수 배열 길이를 구함.
// 마지막 주가 다음 해 1주일 수 있음. (시작 주보다 끝 주가 숫자가 작을 수 있다!)
const week_num =
      (start_week > end_week ? 53 - start_week : end_week - start_week) + 1;

// 이번 월에 몇번째 주가 들어가는지 배열로 만듦,
const _week_arr = Array.from({ length: week_num }, (v, i) => start_week + i);

// 주마다 7개씩 날짜를 넣어주면 끝!
const week_arr = _week_arr.map((week_index) => {
  return (
    <Grid
      key={`${moment(today).format('MM')}_week_${week_index}`}
      margin="4px auto"
      flex_direction="row"
      >
      {/*한 주는 7일이니, 주에 7개씩 날짜 칸을 넣어준다. */}
      {Array.from({ length: 7 }, (v, i) => i).map((day_index) => {
        let _day = today
        // today 본래 값이 변형되지 않도록 clone 메서드 이용
        .clone()
        .startOf('year')
        .week(week_index)
        .startOf('week')
        .add(day_index, 'day');

        const is_today =
              moment().format('YYYY-MM-DD') === _day.format('YYYY-MM-DD');

        ...

        return (
          <Grid
            margin="0px 2px"
            key={`${moment(today).format(
              'MM',
            )}_week_${week_index}_day_${day_index}`}
            flex_direction="column"
            bg={is_today ? '#F7F7FA' : '#ffffff'}
            justify_contents="center"
            style={{ position: 'relative' }}
            >
            {_day.format('MM') === moment(today).format('MM') && (
              <React.Fragment>
                <Text type="label" color="rgba(0,0,0, 0.6)" fontSize="14px">
                  {_day.format('DD')}
                </Text>
                <React.Fragment>
                  {_routineList && routineList}
                  {_challengeList && challengeList}
                </React.Fragment>
              </React.Fragment>
            )}
          </Grid>
        );
      })}
    </Grid>
  );
});

const dow = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((_d) => {
  return (
    <Grid
      margin="4px 2px"
      width="100%"
      flex_direction="column"
      bg="#F7F7FA"
      height="auto"
      key={`${moment(today).format('MM')}_week_${_d}`}
      >
      <Text bold type="label" color="#000" fontWeight="bold">
        {_d}
      </Text>
    </Grid>
  );
});
profile
빠굥

0개의 댓글