투두 리스트가 있는 캘린더

Bam·2023년 5월 17일
0

projects

목록 보기
2/4
post-thumbnail

📅기획의도📅

지난번의 타이머 앱처럼 리액트에 대한 감을 되찾고자, 간단히 진행해 보았습니다.

투두 리스트는 일반적으로 날짜 개념이랑 엮어서 많이 쓰는데, 기존에 클론 코딩했던 Velopert님의 투두 리스트를 다시 한 번 더 클론 코딩하면서 기능을 추가해 보았습니다.


📅프로젝트📅

결과물

날짜에 대한 Todo 정보는 브라우저의 LocalStorage에 저장해서, 서버 없이 배포했으므로 GitHub Pages를 이용했습니다.

만약, 이용 후 로컬 스토리지에 정보가 남는 것이 싫으신 분들은 개발자 도구(F12)의 애플리케이션 탭 -> 로컬 스토리지에서 todo-list의 정보를 삭제해주세요. 추후에 Remove 동작을 하면 로컬 스토리지에서도 삭제되도록 개선할 예정입니다.


사용 기술

  • CSS + SCSS: SCSS를 사용해서 컴포넌트를 스타일링 했습니다.
  • React.js: React.js로 todo list를 만들고, react-datepicker라는 라이브러리를 이용해서 달력 시스템을 가져왔습니다.

기능 소개

Calendar.jsx

메인 화면이자, 모든 동작의 시작이 되는 컴포넌트 Calendar.jsx입니다.

  const [startDate, setStartDate] = useState(new Date());
  const [openTodoList, setOpenTodoList] = useState(false);
  const [todos, setTodos] = useState([]);

  const nextId = useRef(1);
  const modalBackground = useRef();
  const todoData = JSON.parse(localStorage.getItem('todo-data') || '[]');
  • startDate: react-datepicker에서 사용되는 state입니다. 캘린더의 기본 시작날짜(오늘)과 변경되고 선택된 날짜 정보를 담습니다.
  • openTodoList: 날짜를 선택하고 모달창을 열게 만드는 플래그 state입니다. 모달화된 todo list의 조건부 렌더링에 사용됩니다.
  • todos: 모든 todo 정보가 담기는 state입니다.

  • nextId: todo에 번호를 부여하는 ref입니다.
  • modalBackground: 모달창의 바깥 부분을 클릭했을 때, 화면이 닫히도록 조작하기 위한 ref입니다.
  • todoData: todo를 로컬 스토리지에 저장하기 위해 사용되는 변수입니다.
  const onChange = date => {
    setStartDate(date);
    setOpenTodoList(true);
  };

onChange는 date-picker에서 startDate를 변경하기 위해 사용되는 함수입니다. 여기에 날짜를 변경하면 모달창이 열리도록 openTodoList state를 true로 바꿔주었습니다.

  const onInsert = useCallback(text => {
    const todo = {
      id: nextId.current,
      text,
      checked: false,
      month: startDate.getMonth() + 1,
      date: startDate.getDate(),
    };

    setTodos(todos.concat(todo));

    todoData.push(todo);  //로컬 스토리지에 todo 삽입
    localStorage.setItem('todo-data', JSON.stringify(todoData));

    nextId.current += 1;
  }, [todos, startDate, todoData]);

onInsert는 todo-list에서 todo를 추가하는 동작을 담당합니다. todo객체에는 id, 내용인 text, todo의 달성 상태를 나타내는 checked, 날짜 정보를 위한 month/date가 있습니다.

todo를 입력하면 concat()으로 todos에 이어 붙입니다.

그 후 todo를 로컬 스토리지에 넣는 과정을 거칩니다.

  registerLocale('ko', ko); //DatePicker에 한국 시각을 적용하기 위한 locale 설정

  const todoDataOfSelectedDate = todos.filter(todos =>
    todos.month === (startDate.getMonth() + 1) &&  todos.date === startDate.getDate()
  );

todoDataOfSelectedDate는 todos에서 선택한 날짜의 todo 정보를 가져오기 위한 함수입니다. todos의 month와 date를 선택한 날짜의 month, date와 비교해서 일치하는 todo들만 가져와서 렌더링해줍니다.

  return (
    <>
      <Header />
      <div className={'date-picker-container'}>
        <div className={'date-picker'}>
          <DatePicker
            className={'datepicker'}
            locale={'ko'}
            dateFormat={'yyyy년 MM월 dd일'}
            dateFormatCalendar={'yyyy년 MM일'}
            selected={startDate}
            onChange={onChange}
            showIcon
          />
        </div>
      </div>
      {openTodoList &&
        <div
          className={'todo-list-container'}
          ref={modalBackground}
          onClick={e => {
            if (e.target === modalBackground.current) {
              setOpenTodoList(false);
            }}}
          >
          <TodoTemplate>
            <TodoInsert onInsert={onInsert} />
            <TodoList
              todos={todoDataOfSelectedDate}
              onRemove={onRemove}
              onToggle={onToggle}
            />
          </TodoTemplate>
        </div>
      }
    </>
  );

컴포넌트 return 구문입니다. openTodoList의 값에 따라 모달화된 todo list가 조건부 렌더링 됩니다.

현재 문제점

수정할 예정인 문제점들입니다.

  1. 각기 다른 날짜에 대해서 id가 1부터 이어져야하는데, 총 갯수를 기준으로 id가 카운트 된다.
  2. 모달에 닫기 버튼을 다는 것도 추가하는 것이 더 좋은 UX를 줄 수 있다고 생각중이다.
  3. Calendar.jsx가 너무 많은 일을 한다.

소감

좋았던 점👍

  • 비록 클린 코딩의 결과물이었지만, 어떠한 프로그램에 추가 기능을 확장해보는 경험을 할 수 있었다.

  • react-datepicker라는 편리한 라이브러리를 새로 알게 되었다.

    반성할 점👎

  • Calendar.jsx 컴포넌트가 너무 난잡하다. 더 작고, 한 가지 일만 하도록 재사용성을 신경써서 다시 만들어야할 것 같다. -> 즉, 클린 코드는 없었다.

  • 이번엔 사실 react-datepicker라는 라이브러리를 쓸 이유가 전혀 없었다. 차라리 달력을 직접 구현할 걸하는 생각이 완성하고 나니까 들었다.

    총평✍

    사실 처음에는 <DatePicker> 컴포넌트에 inline속성을 주어 항상 펼쳐진 상태의 달력을 구현하려고 했었다.이런느낌으로 가려고 했는데, 이렇게 하니까 startDate의 렌더링 과정에서 문제가 생겼었다.

렌더링 과정이 날짜 클릭 -> 선택된 날짜 선택효과 렌더링 -> 모달 오픈 순서로 이우러져야 했는데, 실제로는 날짜 클릭 -> 모달 오픈 -> 모달을 닫아야 선택된 날짜 렌더링순으로 이루어져서 날짜를 클릭해도 startDate가 업데이트 되지 않는 문제가 있었다.

이것은 <DatePicker/> 컴포넌트 자체의 문제라 inline속성으로 화면을 깔끔하게 만들 수가 없었다.

이러한 문제점 때문에 초기 설계와는 전혀 다른 방향으로 개발해야했고, 결과물도 내 예상과 다른 방향의 물건이 만들어졌다. 이러한 일들을 방지하려면 라이브러리에 대한 조사를 좀 더 면밀히할 필요가 있다고 느끼게 되었다.

그리고 결과물을 확인하니 처음에 생각했던대로 달력을 직접 만들었으면 어땠을까 하는 아쉬운 마음이 남았다.

0개의 댓글