[#4] React로 Task Manager 만들기

오닐·2022년 6월 2일
0

React : Task Manager

목록 보기
4/11
post-thumbnail

🎧1. 오늘의 문제

Diary와 WishList에서 사용할 필터를 Filter로 따로 분리하다 보니 상위 컴포넌트인 Diary와 WishList에 있는 데이터를 사용하기가 어려워졌다. 상위 컴포넌트의 jsx 코드에 여러 state가 사용되기도 하고, 또 context로 받아온 데이터에 따로 함수를 적용하는 등 로직이 복잡해지니 분리하기도 만만치 않았다.
그래서 처음에는 일단은 컴포넌트로 분리하지 말고 Diary와 WishList에 각각 코딩해놓고 나중에 돌아와서 어떻게 분리할지 다시 생각해 보려고 했는데, 그럴 게 아니라 아예 페이지 자체를 컴포넌트화 하면 되겠다는 생각이 들었다. 거기에 필터에 들어가는 optionList랑 함수를 달아 줄 전역 데이터만 props로 받으면 되지 않을까 싶다.


🎧2. Filter -> FilteredList

위와 같은 생각으로 전면수정했다.

//Data
const sortOptionList = [
  { value: "Latest", name: "Latest" },
  { value: "Oldest", name: "Oldest" },
];

const categoryOptionList = [
  { value: "Study", name: "Study" },
  { value: "Daily", name: "Daily" },
  { value: "All", name: "All" },
];

const wishOptionList = [
  { value: "Wish", name: "Wish" },
  { value: "Purchased", name: "Purchased" },
  { value: "All", name: "All" },
];

//Component
const ControlFilter = ({ value, onChange, optionList }) => {
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      {optionList.map((item, index) => (
        <option key={index} value={item.value}>
          {item.name}
        </option>
      ))}
    </select>
  );
};

value만 다르게 해서 같은 형식의 select를 재사용하기 위해 컴포넌트로 분리하고, 나중에 WishList에서도 이 컴포넌트를 재사용하기 위해 미리 wishOptionList도 만들었다.

const [sortType, setSortType] = useState("Latest");
const [categoryType, setCategoryType] = useState("All");
const [wishType, setWishType] = useState("All");

//jsx
<ControlFilter
  value={sortType}
  onChange={setSortType}
  optionList={sortOptionList}
/>
{type === "diary" ? (
  <ControlFilter
    value={categoryType}
    onChange={setCategoryType}
    optionList={categoryOptionList}
  />
  ) : (
  <ControlFilter
    value={wishType}
    onChange={setWishType}
    optionList={wishOptionList}
  />
)}

그리고 ControlFilter에서 사용할 변수들을 동적으로 사용하기 위해 state로 저장한 후, 삼항 연산자를 사용해서 FilteredList가 props로 type='diary'를 받을 경우와 그렇지 않을 경우(WishList)를 나누어서 조건부로 렌더링했다.

const processedList = () => {
    const datefilter = (a, b) => {
      if (sortType === "Latest") {
        return parseInt(b.date) - parseInt(a.date);
      } else {
        return parseInt(a.date) - parseInt(b.date);
      }
    };

    const categoryFilter = (item) => {
      if (categoryType === "Study") {
        return item.category === "Study";
      } else {
        return item.category === "Daily";
      }
    };

    const copyList = JSON.parse(JSON.stringify(list));

    const categoryFilteredList =
      categoryType === "All"
        ? copyList
        : copyList.filter((item) => categoryFilter(item));

    const sortedList = categoryFilteredList.sort(datefilter);
    return sortedList;
  };

최신순과 오래된순, 그리고 카테고리별로 정렬하기 위해 함수를 만들었다. Diary만 우선 만드느라 categoryFilter만 만들었는데, WishList 만들 걸 대비해서 함수도 재사용 가능하게 만들어야 되나 고민하다 간단한 함수니까 그냥 복붙해서 반복하기로 했다. 코딩은 정말 반복 가능한 코드를 만들기 위한 싸움인 듯...

const copyList = JSON.parse(JSON.stringify(list));

이 부분에 사용된 list는 FilteredList 컴포넌트가 받는 props이다. 해당 컴포넌트를 WishList에서도 사용할 예정인데 이때는 diary에 관한 데이터 리스트가 아닌 wishList 데이터 리스트를 사용해야 하기 때문에, 상위 컴포넌트에 그러한 데이터 리스트를 불러오고 필요한 페이지에 적용할 요령으로 만들었다.

{processedList().map((item) =>
                     type === "diary" ? (
  <DiaryBox key={item.id} {...item} />
) : (
  <div key={item.date}></div>
)
)}

processedList 함수를 적용한 값(sortedList)에 map() 메서드를 적용해서 DiaryBox에 전달하는 것까지가 FilteredList의 역할이다. type이 diary가 아닐 경우(WishList)는 아직 구현하지 않아서 대충 key만 넣어주었다.


🎧3. 가벼운 회고

  • SideBar가 열리면 모달창처럼 배경색에 변화주고 사이드바 말고 다른 부분은 못 움직이게(?) 만들어도 좋을 듯.(참고)

  • 파이어베이스랑 연결해서 데이터를 저장해보려고 했는데 이건 모멘텀처럼 개인용 태스크 매니저라서 내가 유저들의 데이터를 관리할 필요가 없다. 그러니 그냥 로컬스토리지에 저장하고, 모멘텀처럼 가볍게 로그인 로그아웃만 구현하자! (처음 접속하면 모달로 로그인 창 띄워주고, 로그아웃 누르면 다시 로그인 창 화면으로 보내기)

  • 다이어리 리스트, 다이어리 작성 페이지, 다이어리 수정 페이지 등에서 공통으로 사용될 데이터는 App.js에 state를 만들어서 관리하고자 한다. Context API를 배운 적 있으니 일단 이걸로 구현하고, 나중에 Redux 배워서 대체해야겠다. 사실 NewDiary랑 EditDiary도 만들었는데 내용이 정리가 안 돼서 5편으로 미뤘다

  • 지금은 임의로 넣어둔 이미지를 랜덤으로 보여주고 있는데 다이어리에 이미지 첨부해서 썸네일로 사용하고 싶다. 이것도 무슨 API를 쓰면 되는 것 같던데 다시 찾아봐야지.

0개의 댓글