
이번 2차 프로젝트에서 쿼리스트링 관련한 기능 구현 부분을 담당했다.
그 중에서도 가장 기억에 남았던 다중필터!
구상한 로직, 코드 공유까지 해보고자 합니다--!
코드를 짜기 전에 전체적으로 어떤 흐름을 가지고 문제를 해결할지 순서대로 정리를 해보았다.
ex)
  {
    sort_type: 'schedules',
    title: '일정',
    contents: [
      '월요일',
        //코드 생략 
      '일요일',
    ],
  },
위의 객체가 여러개로 이루어진 배열의 형태
  const getCardListData = useCallback(async () => {
    const res = await fetch(
      `${BASE_URL}/main/search${search}`
    );
    const data = await res.json();
    setCardList(data.result);
  }, [search]);
  useEffect(() => {
    getCardListData();
  }, [getCardListData]);
🔖 참고)getCardListData함수를 useCallback으로 감싸줌으로써, 해당 컴포넌트가 랜더링되더라도 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환하게끔 한다.(최적화 작업)
  const [clickedCheckList, setClickedCheckList] = useState([]);
   const handleCheckList = (e, content, idx, sort_type) => {
    e.target.checked
      ? setClickedCheckList([
          ...clickedCheckList,
          { id: idx, content, sortType: sort_type },
        ])
      : setClickedCheckList(
          clickedCheckList.filter(list => list.content !== content)
        );
  };
  
    return 
  // 관련 없는 코드 생략
   {contents.map((content, idx) => (
                  <Content
                    key={idx}
                    onClick={e => handleCheckList(e, content, idx, sort_type)}
                  >
                    <input type="checkbox" />
                    {content}
                  </Content>
                ))}
const makeQueryString = () => {
    const queryString = clickedCheckList
      .map(({ id, content, sortType }) => {
        return sortType === 'category' || sortType === 'types'
          ? `${sortType}_id=${parseInt(id) + 1}`
          : `${sortType}=${content}`;
      })
      .map((item, idx) => {
        return idx === 0 ? item : '&' + item;
      })
      .join('');
    navigate(`?${queryString}`);
  };
그러면 다중필터 완성! 💯
위의 코드 아래에 한꺼번에 정리 (관련없는 코드 생략)
const LectureList = () => {
 const { search } = useLocation();
 const navigate = useNavigate();
 const [cardList, setCardList] = useState([]);
 const [clickedCheckList, setClickedCheckList] = useState([]);
 const getCardListData = useCallback(async () => {
   const res = await fetch(
     `${BASE_URL}/main/search${search}`
   );
   const data = await res.json();
   setCardList(data.result);
 }, [search]);
 useEffect(() => {
   getCardListData();
 }, [getCardListData]);
 const makeQueryString = () => {
   const queryString = clickedCheckList
     .map(({ id, content, sortType }) => {
       return sortType === 'category' || sortType === 'types'
         ? `${sortType}_id=${parseInt(id) + 1}`
         : `${sortType}=${content}`;
     })
     .map((item, idx) => {
       return idx === 0 ? item : '&' + item;
     })
     .join('');
   navigate(`?${queryString}`);
 };
 const handleCheckList = (e, content, idx, sort_type) => {
   e.target.checked
     ? setClickedCheckList([
         ...clickedCheckList,
         { id: idx, content, sortType: sort_type },
       ])
     : setClickedCheckList(
         clickedCheckList.filter(list => list.content !== content)
       );
 };
 return (
   <Wrapper>
     <FilterList ref={filterDom}>
       {FILTER_CATEGORYS.map(({ sort_type, title, contents }, idx) => {
         return (
           <Filter key={idx}>
             <Category>
               {title}
             </Category>
             <Contents>
               {contents.map((content, idx) => (
                 <Content
                   key={idx}
                   onClick={e => handleCheckList(e, content, idx, sort_type)}
                 >
                   <input type="checkbox" />
                   {content}
                 </Content>
               ))}
               <Btns>
                 <Button
                   onClick={makeQueryString}
                 >
                   필터 적용
                 </Button>
               </Btns>
             </Contents>
           </Filter>
         );
       })}
     </FilterList>
   </Wrapper>
 );
};
export default LectureList;
const FILTER_CATEGORYS = [
  {
    sort_type: 'category',
    title: '카테고리',
    contents: [
      '국내',
      '일본',
      '유럽',
      '미국',
      '한식',
      '양식',
      '일식',
      '커피·디저트',
      '드로잉',
      '미술',
      '글쓰기',
      '사진',
      '러닝',
      '피트니스',
      '등산',
      '수영',
    ],
  },
  {
    sort_type: 'types',
    title: '클래스 진행 방식',
    contents: ['오프라인', 'VOD', '전자책'],
  },
  {
    sort_type: 'regions',
    title: '지역',
    contents: [
      '서울',
      '경기',
      '인천',
      '부산',
      '경상',
      '대전',
      '걍원',
      '광주',
      '제주',
    ],
  },
  {
    sort_type: 'schedules',
    title: '일정',
    contents: [
      '월요일',
      '화요일',
      '수요일',
      '목요일',
      '금요일',
      '토요일',
      '일요일',
    ],
  },
];
다중필터가 처음에는 괜히 어렵게 느껴져서 손대기조차 두려웠는데 내가 정확히 '어떤 문제'를 해결해야하는지, 어떤 순서로 로직을 짜야할지 처음부터 차근차근 고민하다보니 해결할 수 있었다.
사실 이게 한번 갈아엎은 코드인데, 처음에는 makeQueryString이라는 함수를 만드는 대신에 clickedCheckList를 처음부터 쿼리스트링 형태로 저장했었다. 그런데 생각해보니 checkList내에는 체크리스트 정보만 들어가야하는데, 불필요하게 최종 결과값이 들어가 오히려 코드 가독성이 떨어지고 지저분해보였다. (두가지 관심사가 한 코드 내에 들어감으로써)
어떻게 한 코드 내에 한가지 정보만 넣어줄 수 있을까 엄청 고민 끝에,, 갈아엎었다. 관심사의 분리 어렵지만 항상 고민하고 계속해서 더 좋은 코드 방식을 생각해내보자! 아마 내가 짠 코드보다 훨씬 더 좋은 코드들이 많을 거다..! 다른 방법들도 있는지 더 찾아봐야겠다.