코드스테이츠에서 솔로프로젝트로 쇼핑몰을 만들었다
8일동안 정말 고생을 많이 했다..
처음에 react-router를 설치할때부터 오류가 났으니,,,
한마디로 첫 프로젝트는 오류 범벅이었다
개발속도도 느렸을 뿐더러, 보기좋은 코드를 작성한 것도 아니었다.
북마크 state를 정의할 최상위컴포넌트를 잘못잡아서, 중간에 아예 컴포넌트 props 연결을 갈아엎기도 했다..
(앞으로 꼭 프로젝트 구조도를 작성해야지!)
우여곡절이 많았지만 어찌저찌 그래도 프로젝트를 완성했다.
정말 치열했던, 그리고 어려웠던 8일이었지만 그만큼 배운게 참 많다.
무엇을 배우고 깨달았는지, 그리고 앞으로의 공부방향은 어떻게 잡는게 좋을지 적어보겠다 ㅎㅎ
개발 방법
1. 요구사항들을 메모장에 적은뒤, 하루동안 개발할 기능을 적는다
2. 기능을 개발하다가 오류가 생길경우, 오류를 적고 어떻게 해결했는지도 적는다
3. 관리할 state, 함수, 컴포넌트가 많아진 경우, 구조도를 그림으로 그리고, 어디에 위치해 있는지 확인한다
<나의 원격레포지토리>
https://github.com/jieun9999/fe-sprint-coz-shopping
구현한 기능
1. 페이지를 크게 메인페이지, 상품리스트페이지, 북마크페이지, 총 3가지 페이지로 라우팅했다
2. 메인페이지에서는 상품리스트에서, 북마크리스트 에서 각 4가지 상품을 가져와서 렌더링한다
3. 메인페이지, 상품리스트페이지,북마크페이지에서 상품사진을 누르면 모달창이 크게 뜬다
4. 상품리스트페이지에서 상단에 카테고리 버튼을 누르면, 알맞게 필터링된다
5. 상품리스트페이지에서 상품 하단의 ⭐️을 누르면 북마크에 추가된다. (⭐️을 한번 더 누르면 북마크 삭제된다)
6. 상품리스트페이지에서 북마크가 추가되고, 삭제될때마다 알림토스트가 뜬다
7. 북마크 페이지에서 상단에 카테고리 버튼을 누르면, 알맞게 필터링된다
8. 북마크페이지에서 동일상품이 여러번 추가되지 않게 하기
9. main branch 가 아닌 새로운 브랜치를 만든뒤, pr후 코드리뷰를 받고, main branch 에 merge 하기
10. 나의 로컬레포지토리에서 commit 하기
11. 나의 로컬레포지토리에서 원격레포지토리로 git push 하기
12. 나의 원격레포지토리로 pr 날리기
아직 구현못한 기능
1. 모달창 내에서 북마크를 추가, 삭제하는 기능
2. 무한스크롤
첫 프로젝트를 하면서 깨달은점
한번 프로젝트를 한다고 해서 기능구현을 하는데 완벽해지는 것은 아니지만 코드를 전체적으로 보는 눈이 생기는 중이다!
예전에는 작은 부분을 구현하는데만 신경쓰다보니 크게 보지를 못했다
코드에 문법적인 오류가 있는지 없는지, 테스트가 통과가 되는지, 안되는지만 집중했다
하지만, 쇼핑몰 프로젝트를 만들면서 3개의 페이지, 각각 들어가는 10개가 넘는 컴포넌트, 컴포넌트 간의 props 전달 등을 구현하면서
관계성에 집중해서 보게되었다
1. 프로젝트 구조를 백지에 적고 시작하자
프로젝트 시 관리하는 state, 함수, 변수, 컴포넌트간 수직(포함)관계 등을 백지에 적는다
그래야 앞으로 내가 어떤 컴포넌트를 만들어야 할지, 함수를 어디에 선언해서 어디서 적용해야 할지 정리가 된다.
- 그렇지 않으면 state를 정의한 뒤에도 어디에 쓰였는지, 어디에 앞으로 써야 할지 헷갈리기 시작함, 함수도 중복으로 쓰기 시작함
( hell파티 시작 ㅎ)
- 나중에는 파일이 너무 방대해져서 걷잡을 수 없게 되고, 결국 갈아엎게됨…
2. 작명을 잘하자
함수, state, 변수 작명을 잘해야 헷갈리지 않는다
-만약, 북마크 기능이 있다면 그 기능과 관련된 함수 여러개를 관리하게 된다.
이때, 각 함수가 어떤 역할을 하는지 구분할 수 있도록 작명을 하는 것이 좋다
(ex. onStar = 별모양 아이콘이 켜지는, Category Button = 카테고리를 구분하는 버튼)
3. 스위치(state)는 컴포넌트의 어떤 컴포넌트에 달아야 할지 전체적으로 보고 정의한다 (1번과 연결)
- 처음에는 여기가 스위치(state)를 달아야 하는 부분인지 state의 초기값은 어떤 형태로 정해야할지 (ex. T/F, 배열, 객체 등) 에 대한 감이 없었다
- 그래서 state 정의와 활용 관련해서 기초적인 부분부터 헤메고 다녔다
4. 리덕스를 사용하자. store.js에서 한번에 컴포넌트를 관리하자
- Props driling 방식으로 하니, props가 많아지면서 관리가 불편해졌다
- 다음 프로젝트는 리덕스로 구현해봐야지
5. 외부 api를 어느페이지에서 불러와야 할지, 그 데이터를 어떻게 변수에 담을지도 정리하자
- 데이터를 함수의 인자로 넣어서 딱 렌더링 시키는 것이 fe의 구성
- 데이터를 담는 변수에 대한 정의도 처음에 정리하고 시작 (1번과 연결)
- 나같은 경우는 데이터를 담는 변수를 여기저기에 선언해둬서, 나중에 중복을 줄이는데 시간을 많이 썼음.. (같은 데이터 = 같은 변수)
6. Css 를 공부해봐야겠다
- 강의를 보든
- 이미 존재하는 라이브러리를 쓰든
7. 스타일드 컴포넌트도 처음부터 통일하고 시작하자
- 다른 페이지인데 같은 컴포넌트인 경우, 스타일링을 고수하는 경우가 많은데,
그럴때마다 통일을 제대로 안해놓아서 눈대중으로 함…(이러면 안됨)
결론: 1. 백지에 프로젝트 구조를 적어가면서 만든다
(필수 요소: 페이지, 컴포넌트, 함수, 변수, state, styled-component, 외부 api 데이터 등)
2. 모든 요소에 대한 작명을 잘하자
3. 리덕스 쓰자
앞으로의 공부방향
알고리즘 공부와 프로젝트 개발을 병행!
1. 백준, 프로그래머스 등 알고리즘 공부를 해야겠다
특히, 매일 1시간 이상씩 꾸준히 문제를 풀어야 겠다 (같은 문제라도 다른 사람의 풀이를 살펴보면서)
2. props driling이 아닌 redux로 프로젝트를 만들것이다
props driling은 여러 컴포넌트를 관리하는데 불편한 점이 많다.. (왜 리덕스가 어렵지만 자주 쓰이는지 알것 같음)
3. 쇼핑몰이 아닌 다른 주제로 프로젝트를 만들어보자.
현재 생각하고 있는 주제는 '고민털어놓는 챗봇' 이다.
이름은 임금님 귀는 당나귀귀~! 라는 귀여운 스토리텔링과 어울리는 상담챗봇을 만들어보고 싶다 !
8일동안의 기록
깨지고,또 깨졌다.
5.17 (수)
구현할 기능
1. 클릭했을때 모달이 떠야한다
handleClick 함수를 만들어보자
id를 상태변수로 만들어서
클릭할때마다 products의 특정 배열의 id가 달라질때마다 다른 이미지를 추출하여 모달창에 보여줄순 없을까?
Fe-sprint-cmarket-hooks 의 pages 의 itemListContainer의 handleClick 함수와 인자를 잘 살펴보면서
클릭 이벤트가 일어날때, 그 때의 id를 잘데려올 수 있도록
코드를 짜본다
아마 Main.js 안에 const handleClick이라는 이름으로 함수를 만들어야 하고,
Let findNumber 값을 구해서 몇번째 아이템(인덱스)인지를 알아내고,
ㄴㄴ find 메서드로 아이디를 알아내서 첫번째 객체, 두번쩨 객체 이런식으로 떼어내서 생각해야 함
Return 문에서 handleClick이 진짜 실행되는 부분에 넣어준다
+ modal instance 는 참고만 하는거지, 일일이 다운받아서 하는게 아닌듯,,,,
오늘 2시까지 pr 날리기
2. 모달을 중앙으로 옮기고 싶다 + 모달 디자인
5.18 (목)
1.top buttons는 재사용할 가능성이 있으니 컴포넌트로 만든다
2.상품리스트 페이지에 state를 어떻게 달지?Top buttons를 클릭할때마다 원래 state가 ‘전체’ 이던 것이, 버튼을 누를때마다 그 Top button의 type을 state로 갖도록 설정해준다
3.메인페이지에서 상품리스트를 렌더링하는 조건과(type이 brand 이면 ~ 속성을 렌더링)
상품리스트페이지에서 상품리스트를 렌더링하는 조건이 다르다(type이 brand인 객체들만 렌더링)
4.State와 배열 데이터의 type이 같을 경우에만,배열데이터의 상품을 내보낸다 (이때, filter와 map 메소드를 각각 사용한다)
filteredProducts 라는 변수에 배열데이터의 type과 state가 같은 상품정보들만 담는다
return 문에 가서 filteredProducts 라는 변수에 map 함수를 써서, 모든 원소들을 한번씩 돌면서 상품데이터들이 렌더링 되도록 만든다.
5. 각자 다른 속성을 가지고 있는 객체가 5개이상일 경우에.
자세히 말하자면 category 속성이 달라질때마다 그 객체에 딸린 다른 속성들도 다 다른 경우는?
filteredProducts.map() 내에 if 조건문을 작성하여 product.type에 따라 다른 리턴문을 작성합니다
6. Productlist 페이지 가서 모달창 구현하기
7.topbuttons 를 누를때 스타일이 적용되었으면 좋겠음
문제: 1. 클릭할때 5개가 동시에 스타일적용됨
2. 같은 버튼을 2번누르면 다시 스타일이 풀림=> 한번에 공통적인 className이 적용되는 것이 문제임
각 버튼마다 별도의 isActive 상태를 가지도록 수정해야 합니다.
문제: 두번을 눌러야지만 버튼의 css가 뜨는 문제 <button onClick={()=>{buttontype('All'); buttonActive(0,'All')}}
여기서 두개의 함수가 동시에 작동되려고 하니까 문제가 발생하는거 아닐까?
=> 버튼을 한 번 클릭할 때 클래스 이름이 추가되지 않는 이유는 다음과 같습니다.
buttonActive 함수 내에서 isActive 배열을 업데이트한 후에 setIsActive를 호출해야 합니다.
그러나 현재 코드에서는 setButtonType와 setIsActive를 동시에 호출하고 있기 때문에 상태 업데이트가 제대로 이루어지지 않을 수 있습니다.
문제: 첫번째 클릭때는 렌더링되는 상품에 효과가 적용되고,
두번째 클릭시에 버튼에 css가 적용된다
해결됨!!
const handleButtonClick = (index, type) =>{
setButtonType(type)
if(type === buttonType){
let newIsActive = [...isActive];
newIsActive.fill(false);
newIsActive[index] = true;
setIsActive(newIsActive);
}
}
여기서 if 조건문을 삭제하고, setButtonType(type); 이 것을 맨 밑으로 추가해줬음!
왜 두번째 클릭시에만 className이 추가되었냐면
첫번째 클릭에서는 buttonType이 업데이트되지 않아서 isActive 상태가 업데이트 되지 않고,
두번째 클릭에 이르러서야 이전에 업데이트된 buttonType과 type이 일치하여
isActive 상태가 업데이트 됩니다.
추가질문) 여기선 쓰인 순서대로만 보면 setButtonType(type) 이 제일 위에 있는데, 왜 첫번째 클릭에서는 buttonType이 업데이트되지 않는다고 한거야? state 변경함수가 if 조건문보다 속도가 느려서 그런거야?
답변) useState의 state 변경함수인 setButtonType 함수는 비동기적으로 동작합니다.
즉, setButtonType 함수를 호출하면 상태 업데이트가 예약됩니다.
따라서, setButtonType 함수를 호출한 직후에는 ‘buttonType’의 값이 즉시 업데이트 되지 않습니다
첫번째 클릭에서의 동작순서는 다음과 같습니다.
1. handleButtonClick 함수가 호출됩니다.
2. setButtonType(type) 를 통해 buttonType 값 업데이트를 예약합니다(즉시 변경X)
3.if 조건문을 실행하여 type과 buttonType을 비교합니다.
4.첫 번째 클릭에서는 이전의 buttonType 값과 type 값이 다를 것이므로, 조건문은 false가 됩니다.
5.따라서 isActive 상태가 업데이트되지 않습니다.
두 번째 클릭에서의 동작 순서는 다음과 같습니다:
1. handleButtonClick 함수가 호출됩니다.
2. setButtonType(type)을 통해 buttonType 값이 이미 업데이트되었습니다
3. if 조건문을 실행하여 type과 buttonType을 비교합니다.
4. 이전의 buttonType 값과 type 값이 동일할 것이므로, 조건문은 true가 됩니다.
5. isActive 상태를 업데이트하여 해당 버튼을 활성화합니다.
<2차 코드리뷰>
문제: Itemrender가 main 페이지에서 잘 작동이 되다가 productlist에서는 작동이 안된다
props: state는 main에서 생성하고 하위 컴포넌트인 Itemrender에게 넘겨 주었다.
이제 Productlist 페이지에서 Itemrender 컴포넌트를 쓰려고 하니 문제가 생겼다.
Props 가 잘 전달이 안되는 것 같다
새로운 페이지에서 각각 api 를 불러온다
Main 에서 api 를 불러와서 데이터를 뽑은 것처럼
Productlist 에서도 api를 불러와서 데이터를 뽑는다
Productlist 에서
Main 에서 만든 products, setSelectedProductId 를
인식을 못한다
Productlist 에서 새롭게 state를 만든다
똑같이 작명 가능(const)
app에서 api 하는 것이 안좋으니
Main 에서는 4개를 뽑았지만
100개를 한번에 가져와야 하는데
Url 을 어떻게 바꾸죠?
?count=4을 삭제해서 100개가 한번에 나오도록!
5.21 (일)
- [✔️] 아이템 컴포넌트: Itemrender.js와 Itembybuttons.js에서 별표시(북마크)를 달아준다.
- [✔️] 별표시가 클릭되면, 색깔이 노란색으로 변하고, 추가 알림토스트 추가된다.
별표시가 다시 클릭되면, 색깔이 회색으로 변하고, 삭제 알림토스트가 추가된다
- [✔️] 모달창 컴포넌트: ‘x’, 별표시, 애플워치스트랩(이름명) 등 스타일링을 해준다
- [✔️] 상품리스트 페이지: 각 상품에 존재하는 북마크 버튼을 눌러 원하는 상품을 북마크 할 수 있어야 한다.
이미 북마크 된 상품의 경우, 북마크 버튼에 표시를 해주어야 하며 다시 한 번 북마크 버튼을 클릭 시 해당 상품을 북마크에서 삭제한다.
- [✔️] 상품리스트 페이지: 북마크 버튼을 클릭하여 북마크에 추가 할 때 그리고 삭제할 때는 사용자에게 알림 토스트가 표시되어야 한다.
5.22(월)
- [✔️] 오류해결: 왜 위의 코드에서는 내가 클릭한 <IconContainer> 안의 <img>의 src imgOn으로 나타나는 것이 아니라,
다른 엉뚱한 <img>의 src imgOn으로 나타날까?
- 전체에서 세번째 상품인 아이폰 13, 상품 카테고리 기준 첫번째에 위치한 아이폰 13을 누르면, 세번째 상품의 별표시가 켜진다. 아마 별표시가 만들어지는 기준을 전체의 배열로 통일하면 안될 듯하다.
-filteredProduct를 기준으로 isOnList 라는 state와 useEffect를 만든다
상품 카테고리마다 state를 다 다르게 만들어야 하나..
별표시는 안 나타나도 toast가 잘못뜨는 걸 보니
=> 북마크 상태와 북마크 함수는 모두 App.js 파일에 만들어야 한다.
어떤 컴포넌트를 어떤 페이지에 어떤 함수와 함께 배치해야 할지
어떤 상태는 어느 상위 컴포넌트에서 관리할 지를 생각해봐야 함
- [✔️] 네, 맞습니다. App.js 파일이 최상위 컴포넌트로 사용되고 있는 경우, 북마크 상태를 App.js에서 관리하는 것이 좋습니다.
이렇게 하면 북마크 상태가 메인 페이지, 상품 리스트 페이지, 북마크 페이지 모두에서 공유될 수 있습니다.
- [✔️] 컴포넌트 내의 상태, 함수 관련 정리하기 - 상위 컴포넌트인 App 에서 북마크 관련 기능(상태, 함수) 등을 재 정의하고,
작동시킴
5.23(화)
- [✔️] 북마크 추가,삭제 함수를 어떻게 활용할지 생각해 보아야 한다
- [✔️] 로컬스토리지를 사용해서 전체 버튼시 상품이 추가되거나 삭제된다.
- 별모양 표시가 켜지고 꺼지는 것 과 북마크 로컬스토리지는 state(스위치)를 다르게 사용해야 한다
- [✔️] 로컬스토리지를 사용해서 특정 버튼시, 상품이 추가되거나 삭제 된다
- [✔️] 카테고리나 상품의 페이지가 변하여도 로컬스토리지에 저장된 내역은 그대로 유지되어야 한다.
- [✔️] 새로고침을 하더라도 로컬스토리지는 유지되어야 한다
- [✔️] 오류: 인덱스의 별표시가 on인 경우에, 추가 토스트를 띄우고 인덱스의 별표시가 off 인 경우에 삭제 토스트를 띄운다
추가에서 삭제로 or 삭제에서 추가로, 이렇게 전환되는 구간에만 토스트가 뜬다
5.24(수)
- [✔️] 로컬스토리지 : 이미 상품의 id가 존재한다면 추가하지 않는다.
5.25(목)
- [✔️] 메인페이지: 모든 타입의 북마크 된 상품 정보를 4개 보여준다 (필터기능 없이)
- 보여지는 상품의 타입은 혼합되어 있을 수 있다 (상품, 카테고리, 기획전, 브랜드)
- [✔️] 모달창을 아이템 렌더링 하는 컴포넌트 안에 넣고 사용하는 것이 좋을까?
메인페이지에서 가져오는 형식으로 하면 매번 모달창을 적어줘야 하니까
- [✔️] 북마크 페이지: 상품리스트 페이지에 존재하는 필터링 버튼과 같은 버튼을 이용해 상품을 타입별로 필터해 보여줄 수 있어야 한다.
bookmarks 에는 문제가 없음 출력 잘됨.
그런데 렌더링이 안됨?
=> ItemByButton.js 는 buttonType을 인지하는데, BookmarkList.js 는 buttonType이 undefined로 나온다
이유는?
=> App.js 파일에서 라우팅 Bookmark 컴포넌트에 buttonType={buttonType}을 내려주지 않아서 오류가 생김
모달창이 안뜸?
=> console.log(products) 이 부분이 undefined이기 때문에 삼중연산자식으로 쓰면 안된다
모든 변수가 true나 false 값만 있는 것이 아닌 undefined 나 null 도 존재한다는 점
- [✔️] 아쉬운점 : 전체 버튼과 나머지 버튼에 대해서 조건식을 나누어 썼더니 동일한 기능을 붙일 때 어려움을 느꼈다
모달창에서 북마크 기능 버튼 구현 X
무한스크롤 기능 구현 X
'Code States 44' 카테고리의 다른 글
코드스테이츠 44기 Pre project 회고 (2) | 2023.06.26 |
---|---|
(해결과정기록) 모달창의 입력값을 다른 컴포넌트로 옮기기 (0) | 2023.06.09 |
(프로젝트) 쇼핑몰 만들어보기 (0) | 2023.05.18 |
Section3 기술면접 (0) | 2023.05.09 |
230423 메타인지 스터디 4회차 (0) | 2023.04.23 |