1. (클로닝) 프로젝트 사이트 : 'StyleShare'
"Style Share" 사이트 소개
: 10대 ~ 20대 여자가 대다수 유저인 SNS 연동 커머스 사이트라는 점이 특징
: 자신의 패션 스타일을 SNS로 공유하고, 해당 페이지에 포함되어있는 상품 배너를 클릭하면 상품 페이지로 이동하며, 여기서 구매 시 reward 부여
2. 팀 구성: 프론트엔드 3명 / 백엔드 3명
3. 프로젝트 기간 : 2/15 ~ 2/26 (약 12일)
4. 프로젝트 진행 방식
: Agile(Scrum) 방식, Sprint 주기는 1주일
: 활용 Tool은 notion, trello, slack
: 매일 오전 11시 daily stand up meeting & sprint 주기 별로 정리 미팅(회고)
5. 화면별 업무분담
: 프론트에서 구현해보기로 한 페이지는 아래와 같고,
내가 담당하기로 한 업무 및 페이지는 (1), (2), (4) + 최종 페이지 간 연결 이었음.
(1) SNS 커뮤니티 메인(진입 페이지) : 백엔드 API 통신, 비정렬 정렬, 무한 스크롤 등 포함
(2) 피드 상세페이지 : 피드 내 상품 배너 클릭 시 (6) 상품 상세페이지로 이동
(3) Nav Bar: 이중 map
*(4) Footer
(5) 회원가입/로그인 페이지
(6) 상품 상세 페이지 : 페이지 내 후기 클릭 시 (2) 피드 상세 페이지로 이동
(7) 장바구니6. 기술 스택
- Front-End : React.js, Sass(Scss), React Slick, React-router-dom
- Back-End : Python, Django web framework, Bcrypt, My SQL
- 협업에 사용 된 툴 : Git Hub, Slack, Trello, Google Calender
- Common : RESTful API
: 프로젝트 진행 중 마주 한 문제들과 해결책들을 정리
Problem 1 - 컨텐츠 피드 박스 불규칙 정렬 문제
실제 사이트에서는 각 피드의 높이가 다르고, 일정 간격을 유지하면서 불규칙적으로 정렬이 되어있다.
그런데, flex row 방향으로 정렬하면, 이렇게 각 피드 아래에 빈 공간 영역들이 생기게 된다.
아..빈 공간을 메워야 하는데...Solution 1
짜잔!
.CommunityMain { display: flex; flex-direction: column; justify-content: center; align-items: center; width: 1198px; margin: 20px auto; .Feeds { width: inherit; height: 2700px; display: flex; flex-direction: column; flex-wrap: wrap; } }
flex container의 height를 적당히 한정하고, column 방향으로 정리하니 되긴 되는 듯 한데..
문제는 가져오는 flex 박스 수와 화면 height의 수에 따라서 보여주는 게 지멋대로 바뀜
(아래는 height가 1000px 일때)
(아래는 height가 3000px 일때)
일단은 적정 container box의 height와 해당 box 내에 포함되는 컨텐츠의 수를 무한 스크롤 구현시에도 조절하면 시각적으로는 문제 없을 듯 하니 이대로 가고 추후 다시 생각해보자~
Problem 2 - 모달창 구현 문제
: 컨텐츠 작성 모달창 문제 있었음
(배경을 어둡게 하면 모달창까지 어두워지고, 모달창이 떴을 때 스크롤 바를 없앨수 가 없었음)Solution 2
: overlay역할을 하는 div를 만들어 화면을 가득차게 하고,
isModalOpen boolean 값이 true일 때만 opacity와 background-color를 적용하여 해결
Problem & Solution 3 - 피드 텍스트를 일정 길이만 잘라서 보여주기
: 메인화면에서는 피드의 전체 텍스트를 보여주지 않고 일정 길이까지만 보여주기 위해서 처음 적용시킨 건
.substring() method 였음
: 그러나, 코드 리뷰를 통해 알게 된 css line clamp를 적용해보니, "바로 이거구나!"라고 생각됨. 잘린 부분 이후에는 '...'까지 자동으로 추가됨
Problem & Solution 4 - file type의 input 태그는 직접 디자인이 불가한데.. HOW?
: 구글링을 해본 결과, input 태그는 css로 보이지 않게 숨기고, label을 원하는 대로 디자인하면 됨
: 라벨을 클릭해도 동일하게 파일 첨부 기능 작동! 아.. 그렇구나~
: 파일 첨부시 미리보기 참고 링크
https://basketdeveloper.tistory.com/55 (파일 업로드 방법)
https://velog.io/@chdb57/%E3%85%87-3uk4u6sugu구현 로직
1. input tag 내에 onChange 함수 추가 (파일첨부 시 함수 실행)
2.let reader = new FileReader();
로 파일을 읽고 컴퓨터에 저장할 수 있는 객체를 생성
3. 내장 함수인FileReader.onloadend
(성공적으로 첨부된 파일을 로드 완료 했을 때 콜백함수를 실행)을 실행하고, 그 결과값(reader.result
= 첨부된 파일을 base64 형식으로 encoding 된 데이터)을 변수에 저장
4. 위 변수를 string으로 변환하여 state 데이터로 저장 => 나중에 미리보기 src에 입력 가능
5. 첨부된 파일에 대한 정보를 담은 객체는 event.target.files에 있음 (가장 최근에 첨부된 파일는 [0]번째)
기타 - git을 활용한 코딩 작성 관련 어려움
: git을 활용하여 코드의 버전 관리 할수 있는 점은 매우 유용하고 편리하다고 생각했음
: 그러나, 실제 브랜치를 기능별로 구분하고 코드를 작성하는 과정에서, 명확히 코드를 분리해서 작성하는게 쉽지 않았음
:(예를 들면, '메인 페이지 레이아웃' branch를 구분해놓아도, 모달창으로 뜨는 상세페이지를 하면서 메인 페이지 레이아웃 관련 코드를 수정해야 하는 부분
<느낀점>
: branch 구분을 하는 명확한 기준이 필요할 듯.. 그렇지 않으면, 끊없는 confilct를 해결해야 할 수도..
Problem 5 - 이미지 파일 업로드 기능 구현 (formData 활용)
: 이 부분은 개인적으로 서치하고 학습 중, 구현까지 걸리는 시간, 백엔드 쪽에서도 넘어오는 이미지 파일에 대한 처리에 대해 추가 스터디가 필요한 관계로 2차 프로젝트에서 해결하기로 하고, 첨부 시 미리보기 화면을 띄우는 것 까지만 구현했음
Problem 6 - backend로부터의 전달 데이터 형식
위와 같이 백엔드에서 보내는 json 파일 형식 내의 값을 키 네임 없이 바로 []에 담은후, 프론트에서 전달받아 map을 돌리면,
위와 같이, 0번째, 1번째 값을 가져오지 않고, 스트링에서 첫번쨰인 'h', 두번쨰인 't'를 가져옴Solution 6
: 임의의 키 네임(실제로는 'url')을 각각 할당하여 '키:값' 형식으로 보내면 해결!
Problem 7 - 데이터 내의 일정 depth까지만 접근 가능
백엔드에서 데이터를 수신하여 하나씩 접근 및 가져오는데 첫번째 레벨까지는 문제없이 접근하여 가져오지만, 그 안의 레벨 데이터는 undefined 오류가 나옴
(예를들어, console 창에 찍어보면, feed_basic_data나, feed_comment_data까지는 문제없이 가져오지만, "created_at"이나, comment_list처럼 하위 레벨의 값에 접근하려 하면 "undefined"오류=== 실제 수신하는 백엔드로 부터의 데이터 형식 ===== "current_user_id": 1, "feed_basic_data": { "created_at": "2021-02-24T06:20:53.774Z", "description": "elementum. Etiam semper venenatis ante euismod convallis. Aenean malesuada blandit acc", "feed_id": 6, "feed_user": "styleuser08", "feed_user_id": 8, "feed_writer_about": null, "like_number": 36, "tag_item_number": null }, "feed_comment_data": { "comment_list": [ { "content": "g elit. Cras at rhoncus leo, ut tincidunt el", "created_at": "2021-02-24T06:22:18.022Z", "user": "styleuser09", "user_id": 9 }, { "content": "ctetur adipiscing elit. Cras at rhoncus leo, ut tincidunt el", "created_at": "2021-02-24T06:22:20.995Z", "user": "styleuser07", "user_id": 7 } ], "feed_comment_count": 2 },
Solution 7
- 문제의 원인은 비동기적으로 통신 및 컴포넌트가 리랜더 되면서, 데이터의 depth에 따라 통신하는 시차가 발생
- 따라서, 데이터 수신이 완료된 이후에 접근하도록 하기 위해 동기적으로 처리하는 수단으로 해결
(실제로는 optional chaining('?")으로 해결했지만, 다른 방법도 가능)
Problem 8 - 무한 스크롤 구현
커뮤니티 메인 페이지에서의 비정형 정렬을 위해 container의 Height와 그 안의 피드수를 적정 수준으로 조절하여 원래 사이트와 비슷하게 보여주고 있어서,
스크롤이 하단에 닿으면, container의 크기를 늘려줌과 동시에 피드를 동시에 동일하게 추가해야하는 문제Solution 8
- 테스트 결과 container의 height가 2400px당 약 20개 정도의 피드 수가 채워지면, 실제 사이트와 유사한 정렬이 유지됨
- 따라서, 기본적으로
scrollTop + clientHeight === scrollHeight
여부를 판단하여, 만족하는 경우, 추가로 가져올 feed data를 업데이트하는 동시에 container의 추가 height를 확보하여 계속적으로 동일한 정렬을 유지할 수 있도록 구현- https://velog.io/@hyounglee/TIL-56
Problem 9 - 피드 상세페이지 슬라이드 기능
: 슬라이드를 라이브러리를 활용해 상대적으로 쉽게 구현할 수도 있지만, 직접 수작업으로 한땀한땀 구현해보고 싶은 욕심에서 직접 시도함
: 하단의 썸네일을 클릭하면 바로 그 사진이 메인 큰 사이즈 사진으로 보여지고, 좌우 화살표를 클릭하면 하나씩 사진이 좌우로 넘어가는 애니메이션을 구현해야 했음.Solution 9
: 메인 이미지가 차지하는 공간에 마진없이 가로방향으로 연속적으로 배치되어 있는 이미지 row를 css transform과 transition을 활용하여 자연스럽게 넘어가는 슬라이드를 구현
: 클릭 이벤트와 컨트롤 대상 데이터(이미지)를 유기적으로 연결하고, state를 활용하여, 꽤 성공적으로 깔끔하게 구현완료
Problem 10 - 자식에서 부모로 데이터(id) 전송 및 실행
: 가장 핵심적인 기능인 다른 팀원이 작성한 상품 상세페이지에서 후기를 클릭하면, 해당 상품 배너가 포함되어 있는 피드를 찾아 띄워줘야 하는 기능 구현에서의 문제였음
: 기존에 배웠던 내용은 parent component에서 child component로 데이터를 전달하고자 할때는 props로 전달하는 내용을 배웠고, 당시에 top->down방식으로만 데이터(id)가 전달 가능하다고 배웠기 때문에, 역으로 child에서 2 단계를 올라간 parent component에게 데이터(id)를 통해 피드 상세페이지를 띄워줘야 하는 상황이었음Solution 10
: 마침내, 구글링 결과, child component에서도 자신의 함수 내에 부모에서 내려받은 함수를 포함시켜 실행시키는 방식으로 클릭되는 element로부터 id를 가져와 함수의 인자로서 부모로 데이터를 올려보낼 수 있음을 알아냈고, 적용결과 잘 작동됨!
nav bar
커뮤니티 메인 페이지 비정형 정렬과 무한스크롤
피드 작성 화면
피드 상세페이지 <=> 제품 상세 페이지 전환