[React] 날짜 선택 컴포넌트 만들기 1탄

Yeonsu Summer·2023년 9월 4일
4

React

목록 보기
11/15
post-thumbnail
post-custom-banner

인턴 생활을 시작한 지 벌써 1달하고 2주가 지났다!

회사에서는 프론트엔드 개발자로서 UI 컴포넌트 구현 및 리팩터링을 담당하고 있다.

그 중에서 오늘 만든 날짜 선택 컴포넌트가 인상 깊어서 따로 정리해보고자 한다.

내 개인 프로젝트인 네컷사진에서 날짜 선택 기능을 구현한 적 있는데 자유롭지 못한 포맷이 꽤 아쉬던 기억이 있다.

근데 이번 Task를 통해 더욱 유연한 날짜 선택 컴포넌트를 만들 수 있게 되었다.

지금부터 유연한 DateSelection 컴포넌트를 만들러 가보자!!

1. React 설치 및 파일 생성

// App.jsx
import DateSelection from './components/DateSelection';

function App() {
  return (
    <div style={{ margin: '20px' }}>
      <DateSelection />
    </div>
  );
}

export default App;
// ./components/DateSelection.jsx
import React from 'react';
import { BsFillCalendarHeartFill } from 'react-icons/bs';

const DateSelection = () => {
  return (
    <div>
      <input
        type='text'
        value=''
        placeholder='placeholder'
      />
      <button type='button'>
        <BsFillCalendarHeartFill />
      </button>
    </div>
  );
};

export default DateSelection;

DateSelection 컴포넌트를 사용할 App.jsx 파일과 DateSelection.jsx 파일로 분리한다.

React-icons

npm install react-icons
공식문서에서 더 많은 아이콘을 볼 수 있습니다.

2. 기본적인 기능 구현

// ./components/DateSelection.jsx
...
const DateSelection = () => {
  const [date, setDate] = useState('');

  const handleChangeDate = (e) => {
    const currentValue = e.target.value;
    setDate(currentValue);
  };

  return (
    <div>
      <input
        type='text'
        value={date}
        placeholder='placeholder'
        onChange={handleChangeDate}
      />
      ...

input에 키보드를 입력하면 date, 즉 value가 바뀌도록 한다.

3. 날짜 format 정보 저장하기

// ./components/DateSelection.jsx
const DateSelection = () => {
  const [date, setDate] = useState('');
  const format = 'YYYY-MM-DD';

  const getSeparator = () => {
    const regex = /[^0-9a-zA-Z]+/;
    const match = format.match(regex);

    if (match) {
      const symbol = match[0];
      const indexes = [];

      for (let i = 0; i < format.length; i++) {
        if (format[i] === symbol) {
          indexes.push(i);
        }
      }

      return { symbol, indexes };
    }
    return { symbol: undefined, indexes: [] };
  };

  const separator = getSeparator();
  
  // separator 값이 맞는지 확인
  React.useEffect(() => {
    console.log(separator);
    // { symbol: '-', indexes: [4, 7] }
  }, []);

  ...

날짜 형식인 format을 정한다. (추후에 format을 자유롭게 변경할 수 있도록 한다.)

getSeparator 함수를 통해 format에 사용된 날짜 구분 symbol과 그것의 위치를 담은 indexes를 구한다.

날짜 구분은 숫자나 문자가 될 수 없기 때문에 /[^0-9a-zA-Z]+/과 같은 정규표현식을 사용한다.
matchformat에서 정규표현식에 매치되는 것을 나타내며, ['-', index: 4, input: 'YYYY-MM-DD', groups: undefined]이다.

symbol은 매치되는 기호인 match[0], 즉 '-'이다.

format의 문자를 하나씩 돌려 해당 문자가 symbol 일 경우 해당 위치를 indexes에 넣는다.

정규표현식으로 매치되는 값이 없다면 빈 값을 반환한다.

반환한 값은 separator에 저장한다.

4. 입력 값 formatting하기

// ./components/DateSelection.jsx
const DateSelection = () => {
  ...
  const separator = getSeparator();

  const handleChangeDate = (e) => {
    let currentDate = e.target.value;

    if (separator.symbol && separator.indexes.length > 0) {
      separator.indexes.forEach((index) => {
        if (currentDate.length > index) {
          currentDate =
            currentDate.slice(0, index) +
            separator.symbol +
            currentDate.slice(index);
        }
      });
    }

    setDate(currentDate);
  };

  return (
  ...

input 값을 변경하는 handleChangeDate 함수에 separator가 존재하는 경우에 대한 기능을 추가한다.

separator.indexs를 돌려 currentDatesymbol이 들어가야 하는지 판단한다.

만약 currentDate 길이가 해당 symbol 위치보다 크다면 당 index를 기준으로 currentDate를 나누고 그 사이에 symbol을 넣는다.

예를 들어, '20221010'과 같은 값이 들어오면 '2022-10-10'으로 바꾼다.

5. Calendar 위젯 기능

...
import Datetime from 'react-datetime';

const DateSelection = () => {
  const [date, setDate] = useState('');
  const [open, setOpen] = useState(false);
  ...

  const handleClickButton = () => {
    setOpen(!open);
  };

  const handleChangeCalendar = (selected) => {
    const formattedDate = selected.format(format);
    setDate(formattedDate);
    setOpen(false);
  };

  return (
    ...
      <button type='button' onClick={handleClickButton}>
        <BsFillCalendarHeartFill />
      </button>
      {open && (
          <Datetime
            input={false}
            timeFormat={false}
            dateFormat={format}
            value={date}
            onChange={handleChangeCalendar}
          />
      )}
    </section>
  );
};

export default DateSelection;

text 타입의 input은 달력을 제공하지 않기 때문에 리액트 라이브러리인 react-datetime을 사용한다.

button을 클릭하면 캘린더를 열고 닫히도록 한다.

open 일 경우 캘린더인 Datetime 컴포넌트가 보이며 필요한 props를 넣어준다.
값을 넣는 input은 앞에서 이미 만들었기 때문에 false로 지정한다.
시간 조절하는 기능은 넣지 않을 것이기 때문에 dateFormatfalse로 지정한다.
dateFormat은 위에 미리 선언한 format으로 지정한다.

Datetime 내 날짜를 클릭하면 date가 변경되도록 한다.
formattedDateselected, 즉 선택된 날짜가format에 맞게 포멧팅 된 값이다.
dateformattedDate로 바꾸고 Datetime을 닫아주면 기능이 끝난다.

React-datetime

npm install --save react-datetime
공식문서에서 다양한 속성을 볼 수 있습니다.


이렇게 5단계에 걸쳐 기능을 구현해보았다.

여기에 날짜 유효성 체크와 재사용성을 위한 리팩터링을 해야하는데

그건 2탄에서 해보도록 하겠다!

2탄 포스트 보러가기
3탄 포스트 보러가기

profile
🍀 an evenful day, life, journey
post-custom-banner

0개의 댓글