0. 느낀 점
이번 미니프로젝트를 11/20 ~ 12/01일까지 진행 후 1주일의 리팩토링 기간을 가졌는데 정말 많은 것을 배웠고 또 느꼈던 계기가 되었다. 특히 백엔드와 협업하면서 정말 많은 것을 깨달았고 소통의 중요성도 배웠다.
원래는 마지막에 느낀 점을 쓰려고 했는데 생각보다 길어져서 앞에서 작성하고자 한다. 다른 팀보다 한 명이 부족한 상황에서 초반에 사람이 부족해서 못한 기능을 후순위로 뒀는데(장바구니,예약,예약확인) 원래 맡았던 부분들이 지체 됐다 보니 조급한 마음으로 급하게 후순위를 가져갔고 그래서 내 생각보다 완성도 있게 짜진 못했던 것 같다. 나중에 다같이 도와주더라도 초반 역할 분담은 확실하게 해야 함을 느꼈다. 그리고 백엔드와는 많은 일이 있었지만 결론적으로는 많은 소통을 해가면서 데이터 구조를 미리 정해놓고 같이 api 설계해야 편함을 느꼈다. 백엔드끼리의 같은 기능이면서 상이한 데이터 구조를 받는 일이 많았는데 이러한 부분들도 소통으로 충분히 해결할 수 있었겠다 라는 아쉬움이 들었다. 다른 팀들에 비해 소통이 부족했음을 느꼈고 이 부분은 스스로도 반성을 하고 있다. 내 스스로가 많이 부족함을 느낀 프로젝트였고 더 많은 공부를 해야 함을 느꼈다. 그래도 msw, 무한스크롤 그리고 메인 페이지 등을 통해 css도 향상 시킬 수 있었던 좋은 프로젝트였다고 생각 한다. 오히려 더 공부해야 함을 알려주어서 감사함을 느낀다.
1. 프로젝트 정의
1) 주제 : 숙박 서비스 완성
2) 개발 기간: 23.11.20 ~ 23.12.01
2. 프로젝트 요구 사항 및 구현 사항
◼사용자 인터페이스 예시를 참고하여, 화면을 구성합니다. ☑
◼ API 명세에 따라 백엔드에 전달된 JSON 데이터를 필요에 따라 정돈하여 화면에 출력합니다. ☑
◼ 프론트엔드단에서 유효성 검사를 수행해야하는 지점을 고려합니다. ☑
◼ React.js 또는 Next.js를 기반으로 구현하며, 컴포넌트 단위로 구조를 설계합니다. ☑
◼ (옵션) 페이징 처리 시, 무한 스크롤을 고려합니다. ☑
3. 배포
https://candid-horse-912de6.netlify.app/
Aroom | Aroom에 오신 것을 환영합니다!
candid-horse-912de6.netlify.app
※ 깃허브 레포 링크
https://github.com/so2zy/so2zy_FE
GitHub - so2zy/so2zy_FE
Contribute to so2zy/so2zy_FE development by creating an account on GitHub.
github.com
4. 사용 스택
5. 담당 기능
1) 메인 페이지
- 캐러셀
- 무한스크롤 기능
- 검색/지역 페이지로 연결
- 찜 많은 숙소/판매량 높은 숙소 순으로 보여주기
2) 예약 페이지
- 마크업
3) 장바구니 페이지
- 장바구니 조회
- 장바구니 삭제
- 체크박스 구현
6. 에러 해결
1) 장바구니 체크박스로 필터링을 해줄 때 각각의 아이템들이 걸러지게 해야 했는데 같은 숙소에서 동일한 룸을 두 번 장바구니에 추가 했을 때 필터링이 안되는 현상
roomCartId라는 고유의 값을 백엔드에게 받아와서 이를 필터링 해주었다.
2) 체크박스 선택/해제 기능 구현과 이를 예약 페이지로 데이터를 넘겨줘야 하는 부분
체크박스 선택/해제를 어렵지 않게 생각했지만 막상 백에서 데이터를 받아와서 이를 체크해서 데이터로 넘겨줘야 하는 과정에서 정말 많이 힘들었다.
이 과정에서 자바스크립트의 기본적인 문법들의 중요성을 깨달았고 map 함수부터 .find, .reduce, .forEach 등 기본기의 중요성을 깨달았다.
7. 피드백
1) 무한스크롤
: 처음으로 구현 한 기능인데 초반에 시간을 많이 잡아먹은 것 같다.
문법 자체를 이해하는데 오래 걸렸는데 먼저 getNextPageParam에는 lastPage, allPages , lastPageParam, 이 세 가지가 들어온다.이 getNextPageParam을 통해 페이지를 증가 시켜준다.
- lastPage : fetch 해온 가장 최근에 가져온 페이지 목록
- allPages: 현재까지 가져온 모든 페이지 데이터
- firstPageParam: 첫 번째 페이지의 매개변수
- allPageParam: 모든 페이지의 매개변수
- lastPageParam: 최근에 가져온 페이지의 매개변수
그래서 페이지가 있을 때만 return lastPageParam + 1로 페이지를 증가시켜준다.
그 후 handleIntersect라는 함수로 브라우저에서 위치를 감지 후 다음 페이지를 가져오는 fetchNextPage(); 를 실행 시켜준다. 코드는 아래와 같다.
threshold은 얼마나 보여야 콜백이 호출 될지를 나타내는 기준값이다. 그 후 const UseIntersectionObserver을 선언해줘서 setTarget 함수를 제공해준다. 그 후 위 코드에서 threshold를 0.5로 설정하고 콜백함수인 handleIntersect를 통해 fetchNextPage()를 실행시켜주는 구조다.
2) useMutation
: 이 또한 리액트쿼리 중 하나인데 get을 제외한 post, delete , patch(put) 등을 하고 싶을 때 사용한다.나는 onSuccess에 state로 데이터를 넘겨주었다.
※ put : 전체 내용 수정 / patch : 부분 내용 수정
3) 체크박스
: 쉽다고 생각했는데 이번 프로젝트 하면서 제일 헤맸고 어려웠던 것 같다. 일단 크게 세 가지가 필요 했다.
1) 각각의 체크 선택/해제
2) 전체 체크 선택/해제
3) 같은 숙소를 예약 했을 때 이 것들을 동일하게 처리 하지 않고 각각으로 넘겨줘야 한다.
이 세 가지를 모두 고려하다보니 너무 어려웠다. 백엔드에서 roomId와 accommodationId를 줬는데 이게 고유값이 아니다보니 발생한 문제였다. 그래서 roomCartId라는 값을 따로 더 받아와서 중복 방지 처리를 해주려 했다. 근데 roomCartId 조차 고유값이 아님을 리팩토링 마감 직전에 알아버려서(...) 그냥 포기하고 key값을 만들어줬다.
const [checkedHotel, setCheckedHotel] = useState<{ [key: string]: boolean }>(
{},
);
=> 이렇게 key 값을 가지고 이를 boolean 처리 해준 객체로 생성해주었다.
const handleCheckboxChange = (
accommodationId: number,
roomCartId: number,
roomId: number,
) => {
setCheckedHotel((prevChecked) => {
const key = `${accommodationId}-${roomCartId}-${roomId}`;
const updatedChecked = {
...prevChecked,
[key]: checkedAllHotel ? !prevChecked[key] : !prevChecked[key],
};
return updatedChecked;
});
if (checkedAllHotel) {
setCheckedAllHotel(false);
}
};
const handleAllCheckBoxChange = () => {
setCheckedAllHotel((prev) => !prev);
if (data && data.data) {
const updatedChecked: { [key: string]: boolean } = {};
data.data.accommodationList.forEach((accommodation) => {
accommodation.roomList.forEach((room) => {
const key = `${accommodation.accommodationId}-${room.roomCartId}-${room.roomId}`;
updatedChecked[key] = !checkedAllHotel;
});
});
setCheckedHotel(updatedChecked);
}
};
=> 그 후 숙소id - roomCartId - roomId 로 key를 만들어줬고 updatedChecked를 통해 전체 선택되어 있으면 모든 체크박스가 선택되고 해제될 수 있도록 설정해주었고 이를 checkedHotel에 넣어주었다. handleAllCheckBoxChange 또한 같은 로직으로 구성해주었다.
그럼 내가 체크박스를 선택할 때마다 { 392-123-124 : true , 392-122-124: false } 이런 식으로 나오게 된다. true인 아이템만 따로 모아서 데이터로 넘겨주었다.
4) 고차함수
: 장바구니를 구현하면서 가장 많이 어려움을 겪었던 부분 중 하나다. 생각보다 기본기가 부족함을 느꼈다. 그래서 지금 기회에 총 정리를 해보고자 한다.
- .forEach() : for문을 대체하는 고차 함수, 반복문을 추상화하여 내부에서 주어진 배열을 순회하면서 연산 수행
const numberArr = [1, 2, 3, 4, 5];
let total = 0;
numberArr.forEach((item) => {
total += item;
});
console.log(total); // 15
- .map() : forEach 같이 순회하면서, 콜백함수에서의 실행 결과를 리턴한 값으로 이루어진 배열을 만들어 반환
const numberArr = [1, 2, 3, 4, 5];
const numberMapArr = numberArr.map((item) => {
return (item % 2 === 0) ? 'even' : 'odd'; // 연산한 결과값을 넣어 배열 반환
});
console.log(numberMapArr); // ['odd', 'even', 'odd', 'even', 'odd']
=> forEach와 달리 map은 새로운 배욜이 반환되는 점에서 차이가 있다.
- .find() : 찾고자 하는 값을 그대로 반환한다. 반환값이 true에 해당하는 첫 번째 요소를 반환
const numberArr = [1, 3, 3, 5, 7];
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.find(item => {
return item.age === 20 // 해당조건에 부합하면 item값 반환
}); // {name: "Harry", age: 20}
// find는 하나만 찾음. 뒤에서 배울 filter은 여러개를 배열로
console.log(numberArr.find(item => item === 3)); // 3
console.log(numberArr.filter(item => item === 3)); // [3, 3]
- .filter() : 반환값이 true에 해당하는 요소로만 구성된 새로운 배열을 생성하여 반환
- .reduce() : 콜백 함수의 실행된 반환값을 전달 받아 연산의 결괏값이 반환.
: 첫 번째 인자(accumulator)서부터 시작해서 배열값인 두 번째 인자(currentValue)을 순회하며 accmulator+=currentValue을 실행 => 사실상 forEach, map ,filter 기능을 모두 reduce로 구현할 수 있다.
const numberArr = [1, 2, 3, 4, 5];
const sum = numberArr.reduce((previousValue, currentValue, currentIndex, thisArray) => {
console.log('Current Index: ' + currentIndex + ' / Previous Value: ' + previousValue + ' / Current Value: ' + currentValue);
return previousValue + currentValue; // 연산한 결과값을 누산기previousValue에 넣어 최종값을 얻는다.
}, 0);
console.log('Sum: ' + sum);
/*
Current Index: 0 / Previous Value: 0 / Current Value: 1
Current Index: 1 / Previous Value: 1 / Current Value: 2
Current Index: 2 / Previous Value: 3 / Current Value: 3
Current Index: 3 / Previous Value: 6 / Current Value: 4
Current Index: 4 / Previous Value: 10 / Current Value: 5
Sum: 15
*/
- .sort() : 배열 정렬, 복사본이 만들어지는게 아니라 원 배열이 정렬됨.
- .some() : 배열 메소드인 include()의 콜백함수 버전. 배열의 요소들을 주어진 함수(조건)을 통과하는데 한 개라도 통과하면 true 아니면 false를 출력
const array = [1, 3, 5];
// 짝수인지 체크
const result = array.some((currentValue) => {
return currentValue % 2 === 0;
})
console.log(result); // 리턴 값 : false
// 그 이유는 array의 3개의 요소 모두 2로 나눌때 나머지가 0이 아니기 때문이다.
// 하나라도 부합한 조건에 맞으면 true, 모두 부합하지 않으면 false
// -----------------------------------------------
const array2 = [1, 2, 3, 5];
const result2 = array2.some((currentValue) => {
return currentValue % 2 === 0;
})
console.log(result2); // 리턴 값 : true
// 그 이유는 array의 4개의 요소 모두 2로 나눌때 나머지가 0인 요소가 하나라도 있기 때문이다.
// 하나라도 부합한 조건에 맞으면 true, 모두 부합하지 않으면 false
- .every() : some()의 반대 버전 , 모두 통과할 때만 true , 아니면 false 출력 (빈 배열은 무조건 true)
8. 참고 자료
- 리액트 쿼리
https://github.com/ssi02014/react-query-tutorial
GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리
😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리 - GitHub - ssi02014/react-query-tutorial: 😃 TanStack Query(aka. react query) 에서 자주 사용되는 개념 정리
github.com
📚 JavaScript 배열 고차 함수 총정리
자바스크립트 배열 고차함수 여러분이 자바스크립트를 배우는 중이라면, 고차 함수(Higher-Order Function) 라는 용어를 얼핏 들어본 적이 있을 것이다. 고차 함수란, 함수를 파라미터로 전달받거나
inpa.tistory.com
'패스트캠퍼스 프론트엔드 > 복습' 카테고리의 다른 글
야놀자X패스트캠퍼스 파이널 프로젝트 복습 및 후기 (1) | 2024.01.29 |
---|---|
야놀자X패스트캠퍼스 토이프로젝트2 복습 (0) | 2023.11.17 |
야놀자X패스트캠퍼스 토이프로젝트 1 복습 (1) | 2023.11.03 |
[Web]프로젝트 셋팅 : ESLint & Prettier (0) | 2023.09.28 |