[프로젝트] To Do List 마무리

Jade·2022년 12월 13일
2

프로젝트

목록 보기
4/28

투두리스트 프로젝트를 하면서 느꼈던 점들과 배운 것들, 어려웠던 점들을 정리해본다.

😉 My Github

배포 링크 : https://ansmeer008.github.io/TODO-LIST-APP/

🔥 프로젝트의 목표

✅ Bare Minimum

혼자 해보는 프로젝트였지만 코드스테이츠에서 정해준 가이드라인이 있었다면 'CRUD'가 동작하는 Todo앱을 만들라는 것이었다.

내가 만든 앱에서 CRUD가 동작하는 방식은 아래와 같다.

C : 새로운 할 일 생성, 할 일 완료시 쿠키 생성
R : 할 일 데이터 불러오기, 쿠키 데이터 불러오기
U : 체크 박스를 이용해 할 일을 완료했을 때 체크된 상태로 수정하기 
D : 할 일, 쿠키 삭제 

✅ advanced

  • 상태 관리 : Redux 라이브러리 사용해 리팩토링
  • 캘린더 라이브러리 React-Calendar 사용하기
  • 배포하기


❗️ 추가하고 싶은 기능들

  • 쿠키 발행시에 '쿠키가 발행되었습니다!'라는 알림창 뜨는 기능.
  • 지금은 오늘 일정만 볼 수 있도록 되어 있어서 예전 일정들도 확인할 수 있도록 => 아마 로컬 스토리지로는 부족할 것 같아서 이 경우 파이어 베이스 같은 데이터 베이스가 필요할듯...
  • CSS 리팩토링 (필요없는 className들 수정하거나, 아예 postCss 같은 툴 사용해 좀 더 깔끔한 CSS)


🏛 구조

/
├── node_modules
├── public
│   └── index.html
│
├── src
│   ├── actions
│   │    └── index.js  
│   ├── components
│   │    ├── InputBox.js
│   │    ├── Nav.js
│   │    ├── TodoContent.js
│   │ 
│   ├── pages
│   │    ├── Cookies.js
│   │    ├── Information.js
│   │    ├── Menu.js
│   │    └── ToDoCalendat.js
│   │    └── TodoListContainer.js
│   │ 
│   ├── App.js                           
│   └── index.js 
│   └── App.css     
│
├  .gitignore 
├  package-lock.json 
├  package.json
└  README.md


🔥 고군분투기

🤣 checkbox가 나에겐 왜 그렇게 어려웠는지...

처음 구현할 때도 힘들었고, 리덕스로 리팩토링 할 때도 체크박스 상태를 변경시켜주는 것이 정말 힘들었다. 체크박스는 투 두 목록들 각각이 가지고 있는 것이므로 ToDoContent라는 컴포넌트에 포함된 요소였고, dummy data를 사용할 때는 아래 예시처럼 status라는 키의 값으로 "active","completed"와 같이 문자열을 사용하다가 redux를 사용할 때 boolean으로 바꿔서 사용하기로 했다.

//더미 데이터 예시 

const data = [{
      id: 1,
      content: "장보러 가기",
      date: new Date(),
      status: "active",
    },...]
//Redux Refactoring 후 TodoContent 컴포넌트 

export default function TodoContent({ tododata }) {
  const { id, content, status } = tododata;
  const dispatch = useDispatch();

  const handleChange = () => {
    dispatch(setCheckboxStatus(id));
  };

  const handleDelete = () => {
    dispatch(deleteToDo(id));
  };

  return (
    <div className="content-container">
      <input
        className="content-checkbox"
        type="checkbox"
        id={id}
        checked={status === true}
        onChange={() => handleChange()}
      ></input>
      <label htmlFor={id} className="content-text">
        {content}
      </label>
      <button className="content-delete-button" onClick={() => handleDelete()}>
        <TbTrash />
      </button>
    </div>
  );
}

참고로 체크박스 상태를 변경하는 케이스를 포함하는 todoReducer는 아래와 같이 작성되었다.

import { ADD_TODO, DELETE_TODO, SET_CHECKBOX_STATUS } from "../actions/index";
import { initialState } from "./initialState";

const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TODO:
      return Object.assign({}, state, {
        todo: [
          ...state.todo,
          {
            id: action.payload.itemId,
            content: action.payload.todoContent,
            date: new Date(),
            status: false,
          },
        ],
      });
      break;

    case DELETE_TODO:
      return Object.assign({}, state, {
        todo: state.todo.filter((el) => el.id !== action.payload.itemId),
      });
      break;

    case SET_CHECKBOX_STATUS:
      let idx = state.todo.findIndex((el) => el.id === action.payload.itemId);
      return Object.assign({}, state, {
        todo: [
          ...state.todo.map((el, index) =>
            index === idx
              ? {
                  ...el,
                  status: !el.status,
                }
              : el
          ),
        ],
      });
      break;

    default:
      return state;
  }
};

export default todoReducer;


😅 Redux와의 두번째 만남... 근데 이제 초면같은...

역시 기술은 안 써먹으면 까먹는다고... Redux도 정리해둔 내용을 다시 읽다시피 했다. 한 번 써봤던 거라 익숙하지 않은 부분이 아~예 없다곤 할 수 없겠지만서도, 자주 사용하지 않고 자주 보지 않으면 막막함을 느낄 수밖에 없는 것 같다.

어렵게 느껴졌던 부분은 아무래도 이제 액션들을 정의할 때였는데, 단순히 add, delete만 정의할 것이 아니라 위에서 구현했던 체크박스의 상태를 변경시킬 SET_CHECKBOX_STATUS도 필요했다. 그에 따라서 어떤 것들을 파라미터로 받아와야 이후에 리듀서에서 가공이 가능할지 하나하나 생각하는 과정이 쉽지 않았다.

//action/index.js 파일
export const ADD_TODO = "ADD_TODO";
export const DELETE_TODO = "DELETE_TODO";
export const SET_CHECKBOX_STATUS = "SET_CHECKBOX_STATUS";
export const ADD_COOKIE = "ADD_COOKIE";
export const DELETE_COOKIE = "DELETE_COOKIE";

//todo에 새로운 할 일이 추가되는 행동 (inputbox, todocontent 등에 필요할듯)
export const addToDo = (itemId, todoContent) => {
  return {
    type: ADD_TODO,
    payload: {
      itemId,
      todoContent,
    },
  };
};

//todo에서 할 일을 삭제하는 행동
export const deleteToDo = (itemId) => {
  return {
    type: DELETE_TODO,
    payload: {
      itemId,
    },
  };
};

//todo 속 status 속성을 변경하는 행동
export const setCheckboxStatus = (itemId) => {
  return {
    type: SET_CHECKBOX_STATUS,
    payload: {
      itemId,
    },
  };
};

//cookies에 새 쿠키를 추가하는 행동
export const addCookie = (itemId, cookieIcon, cookieDate) => {
  return {
    type: ADD_COOKIE,
    payload: {
      itemId,
      cookieIcon,
      cookieDate,
    },
  };
};

//cookies에서 해당 id를 가진 쿠키를 제거하는 행동
export const deleteCookie = (itemId) => {
  return {
    type: DELETE_COOKIE,
    payload: {
      itemId,
    },
  };
};



✋ 넌 진짜 처음이지? Redux-persist

로컬 스토리지를 겨우 구현했는데, 막상 리덕스로 리팩토링을 하려니 리덕스에서 로컬 스토리지를 사용할 수 있는지를 몰랐다. 구글링을 해보니 Redux-persist라는 것을 사용하면 된다고 해서 여기를 참고해서 진행하니 정말 마법처럼 ㅎㅎ 로컬 스토리지가 구현되었다. 사실 마법이라고 표현한 것처럼 이 툴에 대해서 잘 알지 못하기 때문에 지금은 별 문제 없이 잘 사용했지만, 다음에 다른 프로젝트에서 사용할 때에는 에러가 발생하거나, 잘 안 맞을 수 있다는 생각도 든다. 뭔가 잘 알지도 못하는 툴을 사용한다는 점이 잘했다고 할 수는 없을 것 같다.



🎨 CSS... 겉과 속이 다른 너...

기능 구현에 힘쓴다고 CSS에는 신경을 못 쓰다 보니 App.css에 몰아서 css를 작성하게 되었는데, 그 과정에서 선택자들이 많아지는 것을 보니... 왜 postcss나 다른 라이브러리를 사용하는지 알 거 같았다. 코드가...많이 더러워졌다.



⌨️ 진짜... 어떻게 하면 좋을지 모를 이 오타....!!!!!!!!!

오타 때문에 시간을 버린 게 한두 번이 아니다... prettier가 있어서 그나마 이정도겠지..? 오늘 리팩토링 할 때는 사실 단순 오타라기 보다는 키 값을 잘못 전달해줬었는데, 그것때문에 정말 내가 똥멍청이라서 해결을 못하는 건가...하면서 좌절하기도 했다. 발견하고 난 뒤의 허무함이란...ㅎㅎ...그래도 해결되어서 다행이라며 웃을 수 있었지만... 이런 오타를 줄일 수 있는 방법을 정말정말 고민해봐야겠다...



🥹 코드 작성 외에도 고난은 찾아온다

어제와 오늘 고난의 흔적을 보시라...
마지막 리덕스 리팩토링을 마무리하고 난 뒤에 이제 배포 링크만 만들면 된다~~ 룰루랄라 하던 나에게 찾아온 것은 수많은 에러들이었다...

분명 그냥 전에 했던 대로 내가 블로그에 써뒀던 글과 노션에 적어뒀던 내용들을 기반으로! 동일하게! 번들링과 배포를 진행한 것 같은데 내 깃허브 페이지 링크는 아래 이미지와 같은 에러들을 콘솔창에 띄운 빈 ! 화 ! 면 ! 만 출력했다.

해결하려고 했던 시도들

  • npm run build를 통해 번들링하고 (pakage.json 파일의 scripts 부분 설정을"build": "BUILD_PATH='./docs' react-scripts build"로 해줌),
    해당 내용을 깃허브에 push 한 뒤, setting => github pages에서 docs 폴더 선택해주기.

  • netlify에서 배포해보기

  • Router에 base를 지정해줘야 한다고 해서 .env 파일을 만들고 PUBLIC_URL을 만들어 과 같은 형식으로 지정해주기.

  • babel.config.js 파일 생성하기

  • BrowserRouter를 HashRouter로 바꾸기

결론적으로 5번 방법으로 배포에 성공하게 되었다.

gh-pages 에서 배포 할 때 react-router-dom 의 BrowserRouter 을 쓰면 화면이 안나오고 에러가 나올 수가 있다고 한다. 그래서 HashRouter를 권장한다고 하는데, HashRouter을 사용하면 URL 에 #이 붙게 된다고 한다.

(사실 HashRouter를 쓰는 대신에 3번을 해줘도된다는 것 같은데...내가 했을 때는 안 됐다... 아마 내가 뭔가를 잘못해서 그런거겠지만...)

두 라우터의 차이점을 찾아보니 아래와 같았다.

  • 해쉬 라우터는 정적 페이지에 적합, 브라우저 라우터는 동적 페이지에 적합
  • 해쉬 라우터는 검색 엔진이 읽지 못하는데, '#' 때문에 서버가 페이지의 유무를 알 수 없다. 그래서 거의 사용하지 않는 것이기도 함.

배포가 계속 실패해서 어제부터 오늘까지 하루종일 뭐가 걸린 것처럼 답답하고 침울했는데... 그래도 결국 해결하고 나니 기분이 정말...상쾌하다.



👼🏻 손을 들어 자신의 머리를 쓰다듬어주세요

그래도 이 모든 게 내 첫 솔로 프로젝트라고 생각하면 견딜만 했다. 처음부터 잘 하는 사람이 어딨냐고 생각하면 또 좀 할 만 했다. 물론 괴물 같은 사람들이 너무 많은 분야라는 건 알지만 알게 뭐람 ~~ 애초에 그런 사람과 나를 비교하는 건 바보 같은 일이라는 걸 잘 안다. 이 프로젝트는 내 시작이고, 출발점이라는 점을 잘 되새기며 이렇게 내 첫 프로젝트를 마무리해보려고 한다.

profile
키보드로 그려내는 일

0개의 댓글