스테이폴리오, 리팩토링 현재진행형 🔥

Seokho·2022년 1월 14일
0

STAYFOLIO Project

목록 보기
2/3
post-thumbnail

왜 리팩토링을 할까?

스테이폴리오를 모티브로한 프로젝트인만큼 구조와 기능을 최대한 참고했다. 특히 조건부 필터링 페이지를 맡은 나는 API호출, 쿼리스트링 등 처음 접하고 어려운 파트를 학습했는데, 작업하다 보니 이상한점을 발견했다.

현재 스테이폴리오 웹사이트이다. 잘보면 나는 'SEARCH버튼'을 사용하지 않았음에도 주소창에 쿼리스트링이 붙고 API호출된다.
그래 그럴수도 있지! 라고 생각했지만 프로젝트 중반쯤부터 상당히 거슬렸다. 그럼 대체 저 'SEARCH버튼'은 왜 있는거지? 없어도 되지 않나? 존재 이유가 없고 기능이 불분명하다고 느꼈다.
나는 단순 클론을 하는 것은 큰 의미가 없다고 생각한다. 항상 '왜?' 라고 고민하고 문제점과 불편한점을 찾아 개선하는 것이 개발자의 자세라고 생각하기에 리팩토링을 진행하게 되었다.

Overview

✔️ Query String 및 데이터를 활용하여 조건에 맞는 호텔 리스트 시각화

실제 스테이폴리오 웹사이트의 구조와 동일하게, “적용하기 버튼”을 클릭 시 query string을 붙여주고 query string이 변경되면 useEffect에서 API호출했다.
하지만 이러한 구조를 유지한다면 “SEARCH 버튼“의 존재 이유가 불분명하여 좋지 않은 UI라고 판단했다.
이를 해결하기 위해 “적용하기 버튼“을 클릭 시 모달창만 닫아주고, “SEARCH 버튼“을 클릭 시 API호출하도록 리팩토링 중이다!

이전 코드

자식 컴포넌트에서 적용하기 버튼을 클릭하면 handleFilter가 실행되고 주소창에 쿼리스트링이 붙여진다.

사실 이번 프로젝트를 진행하면서 모든 웹사이트의 주소창에 쿼리스트링이 무조건 붙어야된다고 착각하고 있었다. 프로젝트 당시에는 쿼리스트링에 목숨걸고 달려들었는데, 참 바보같은 짓이었다.

쿼리스트링은 URL의 뒤에 입력 데이터를 함께 제공하는 가장 단순한 데이터 전달 방식일뿐, 그리고 필요에 의해 사용하는 선택이며 절대적인 필수요소가 아니었다. 오히려 기준없이 사용하면 보안에 위협이 될 수도 있고, 데이터를 읽는데 많은 시간이 소요될 수 있다고 한다.

--부모--
const handleFilter = stateObj => {
    const URLSearch = new URLSearchParams(location.search);
    Object.entries(stateObj).map(([key, value]) => {
      if (typeof value === 'boolean') {
        value && URLSearch.append('category', key);
      } else {
        value && URLSearch.append(key, value);
      }
    });
    navigate(`/list?` + URLSearch.toString());
    closeHandler();
  };

useEffect(() => {    fetch(`http://10.58.5.136:8000/stays${location.search}`)
      .then(res => res.json())
      .then(res => setHotel(res.data));
  }, [location.search]);

<ModalBtn onClick={() => clickHandler(0)}>
  인원
  <MdOutlineKeyboardArrowDown />
</ModalBtn>
{currentID === 0 && (
  <SelectPeople
    closeHandler={closeHandler}
    handleFilter={handleFilter}
  />
)}


--자식--
const useCounter = () => {
  const [quantity, setQuantity] = useState({
    adult: 0,
    child: 0,
    baby: 0,
  });
  
  export default function SelectPeople({ closeHandler, handleFilter }) {
  const { quantity, plusQuantity, minusQuantity } = useCounter(0);

<ModalPeopleBtn onClick={() => handleFilter(quantity)}>
          적용하기
        </ModalPeopleBtn>
}

리팩토링 코드

이번 리팩토링의 가장 중요점은 '적용하기 버튼'이 아닌 'Search 버튼'을 통해 API호출을 하는 것이다. 일단 주소창에 붙는 쿼리스트링 handleFilter함수를 버렸다. 그리고 부모 컴포넌트에서 사용할 기본값 quantity를 가져왔고, getSelectedPeople함수로 적용하기 버튼을 클릭 했을 때 단순히 모달창이 꺼지도록 만들었다.

가장 중요한 'Search 버튼'이 API를 호출할 수 있도록 fetchSearchResult 함수를 만들었다. 인원 모달창에서 인원을 선택하면 quantity에 정보가 저장되고, 'Search 버튼'을 클릭하면 이 정보가 adult=${quantity.adult}&child=${quantity.child}&baby=${quantity.baby} 이렇게 쿼리스트링으로 API를 호출하게 된다.

--부모--
const [currentID, setCurrentID] = useState();
const [quantity, setQuantity] = useState({
    adult: 0,
    child: 0,
    baby: 0,
  });

const getSelectedPeople = () => {
    setCurrentID(false);
  };

const fetchSearchResult = () => {
    fetch(`http://ec2-3-36-124-170.ap-northeast-2.compute.amazonaws.com/stays?
adult=${quantity.adult}&child=${quantity.child}&baby=${quantity.baby)
      .then(res => res.json())
      .then(res => setHotel(res.data));
  };

<ModalBtn onClick={() => clickHandler(0)}>
  인원
  <MdOutlineKeyboardArrowDown />
</ModalBtn>
{currentID === 0 && (
  <SelectPeople
    closeHandler={closeHandler}
    getSelectedPeople={getSelectedPeople}
    quantity={quantity}
    setQuantity={setQuantity}
  />
)}

<SearchBtn onClick={() => {fetchSearchResult();}}>
          SEARCH
</SearchBtn>


--자식--
<ModalPeopleBtn onClick={() => getSelectedPeople()}>
          적용하기
        </ModalPeopleBtn>

완성!

아직 인원 모달창만 리팩토링한 상태고, 나머지는 천천히 진행 예정이다. 신입 프론트엔드 개발자에게 바라는 최대 능력치가 API 잘 다룰수 있는 역량이라고 들었다. 정확한 개념을 갖추고 눈감고도 기능을 구현할 수 있을때까지 열심히 달려봐야겠다!
아무쪼록 데이터 아주 잘 받아와지고, 200 ok 뜬다! 😎

profile
같이의 가치를 소중하게 생각하는, 프론트엔드 개발자 이석호 입니다.

0개의 댓글