Task Management App #1

4월 3일(일)

github 리포

기능

  • 새로운 할 일 추가
  • 기존 할 일 수정
  • 할 일 지우기
  • 할 일 상태 변경

할 일 데이터

task: {
  "id": number,
  "name": string,
  "start": number,
  "end": number,
  "type": string
}
  • type: doing, completed, incompleted로 나뉘고 종류에 따라 색이 달라지고 시간이 지났는데 마치지 못한 할 일은 따로 표시한다.

시간 유효성 검증

  • 할 일을 추가할 때나 할 일 시간을 수정할 때 시간 유효성을 검증해야 한다.
  • 시간 유효성1) 9시에서 24시 사이만 사용한다.
  • 시간 유효성2) 시작 시간은 끝나는 시간보다 빨라야 한다.
  • 시간 유효성3) 이미 사용 중인 시간은 사용할 수 없다.

시간 유효성 검증 방법

9시에서 24시 사이만 사용한다.

HTML <input> 태그의 min, max attribute를 사용하였다.

<label htmlFor="task-start">시작:</label>
<input id="task-start" type="number" min="9" max="24" />

시작 시간은 끝나는 시간보다 빨라야 한다.

나머지 두 개의 유효성 검증은 함수로 만들었다.

const isValidTime = (id, start, end) => {
    if (start >= end) {
      return { status: 'error', message: '끝나는 시각이 시작 시각보다 느려야 합니다.' };
    }

    return { status: 'ok', message: '성공적으로 할 일이 추가되었습니다.' };
  };

isValidTimeid, 시작 시각, 끝나는 시각을 인자로 받는다. id는 유효성3 검증에 사용된다. status와 message를 프로퍼티로 갖는 객체를 리턴한다.

이미 사용 중인 시간은 사용할 수 없다.

이미 사용 중인 시간을 체크할 때 할 일을 추가와 할 일 수정의 로직이 다르다.
할 일을 수정할 경우 해당 할 일이 기존에 사용하고 있는 시간을 사용하지 않는다고 표시한 후, 확인을 해야한다.
반면, 할 일 추가는 기존의 사용 중인 시간이 없기 때문에 점유 중인 시간 할당 작업이 필요없다.

const isValidTime = (id, start, end) => {
    if (start >= end) {
      return { status: 'error', message: '끝나는 시각이 시작 시각보다 느려야 합니다.' };
    }

    const _schedule = [...schedule];
    if (id !== null) {
      const { start: _start, end: _end } = tasks.find(task => task.id === id);

      for (let i = _start; i < _end; i++) {
        _schedule[i] = false;
      }
    }
    for (let i = start; i < end; i++) {
      if (_schedule[i]) {
        return { status: 'error', message: '이미 할 일이 있는 시각입니다.' };
      }
    }

    return { status: 'ok', message: '성공적으로 할 일이 추가되었습니다.' };
  };

새로운 할 일은 id 인자 값을 null로 전달하여 구분한다.

좋은 방법인지 잘 모르겠다.

id가 있다면 해당 아이디에 해당하는 할 일이 점유하고 있던 시간을 할당 해제해준 뒤 겹치는 시간이 있는지 찾아준다.
id가 null이라면 겹치는 시간이 있는지 바로 찾아준다.

schedule 배열은 App 컴포넌트의 state이기 때문에 변경을 하지 않기 위해 _schedule 지역 변수를 만들어 구조 분해 할당하여 사용하였다.

할 일의 배치

  • 배치 규칙1. 할 일은 시간 순서를 갖는다.
  • 배치 규칙2. 시간표는 9시에 시작하고 같은 시간 차이가 나면 같은 간격을 가져야 한다.

할 일은 시간 순서를 갖는다.

할 일을 수정하거나 추가할 때 항상 할 일을 시작 시간 기준으로 정렬해주었다. 겹치는 시간은 없기 때문에 시작 시간 순으로만 정렬해주어도 충분하다.

const addTask = (name, start, end) => {
    const _tasks = [...tasks, { id: Date.now(), name, start, end, type: 'doing' }];
    _tasks.sort((a, b) => a.start - b.start);
}

const editTask = _task => {
  const _tasks = tasks.map(task => (task.id === _task.id ? _task : task));
    _tasks.sort((a, b) => a.start - b.start);
}

시간표는 9시에 시작하고 같은 시간 차이가 나면 같은 간격을 가져야한다.

  • 할 일을 배치는 두 가지를 신경썼다. 1. 높이, 2. 위치
  • 높이는 end - start를 사용하여 시간을 구했고 간격은 각 시작 시간과 끝 시간의 차이를 구해서 margin-top으로 적용했다.
const [marginTops, setMarginTops] = useState([]);

useEffect(() => {
  let prev = 9; // 시작 시각은 9시
  let res = [];

  tasks.forEach(({ start, end }) => {
    res = [...res, start - prev];
    prev = end;
  });

  setMarginTops(res);
}, [tasks]);
  • marginTops는 각 task 컴포넌트를 호출할 때 같이 넘겨준다.

좋은 방법인지 모르겠다. Task state에 프로퍼티로 넘겨주는 방법과 고민했는데 state에 프로퍼티로 가져야 할 정보인지 의문이 들어 따로 구해주었다.

고민

  • 시간 유효성 검증을 위해 배열을 만드는 것이 가장 효율적이고 효과적인 방법인가?
  • schedule state는 tasks state에 종속적이다. 현재는 변경될 때 두 state를 각각 변경하는데 실수가 발생할 여지가 많은 건 아닐까?
  • schedule을 변경할 때 task의 프로퍼티를 사용하기 때문에 둘이 일치한다고는 어느정도 자신할 수 있지만 여전히 종속적인 schedule state가 반드시 필요한지는 의문이다.

Modal

  • 현재 새로운 할 일을 추가하는 모달과 기존 할 일을 수정하는 모달 두 가지를 같은 Modal 컴포넌트를 사용한다.
  • editModal
<Modal
  mode={mode}
  key={edittingId}
  task={tasks.find(({ id }) => id === edittingId)}
  selectEdittingId={selectEdittingId}
  toggleMode={toggleMode}
  isValidTime={isValidTime}
  onEditting={editTask}
/>
  • addModal
<Modal
  mode={mode}
  toggleMode={toggleMode}
  isValidTime={isValidTime}
  onAddTask={addTask}
  task={{ name: '', start: 9, end: 10 }}
/>
  • 중복되지 않는 props가 많은데 이렇게 사용하는 것이 효율적인지 고민이 된다.
  • Modal 안에서 사용되는 state가 동일하고 대부분의 함수가 비슷하기 때문에 같이 사용하는 것이 따로 만드는 것보다는 좋은 것 같다.
  • 공통적인 Modal을 작성하고 추가로 상속하는 모양을 고민해봐야겠다.

🤔 아직 리액트 경험이 부족해 고민민 많고 진도를 나가는게 힘든 것 같다.

좋은 웹페이지 즐겨찾기