위코드에서는 첫 달은 기초를 배우고 적용하는 데에 집중한다. 적용하는 과정이었던 인스타그램 클론이 끝이 났고, 그동안 미루었던 리뷰를 해보려고 한다.
처음에는 HTML/CSS와 JavaScript만 가지고 약 1주간 인스타그램을 클론 했었지만 React와 SASS로 옮기고 나서 처음에는 CSS보다 어려운 것 같고 HTML이 더 쉬운 것 같고, 기능 구현하기도 쉽다고 생각했었다. 하지만 금방 익숙해지게 되었고 이래서 싸쓰 싸쓰 리액트 리액트 하는구나 하고 느꼈다. ㅋㅋㅋ
우선 이번 cloning 과제는 복잡한 기능을 구현하는 것에 초점을 두지 않고 기본적으로 SASS와 React에 익숙해지고 state, props, map 함수 사용 등 간단한 기능을 구현하는 것에 집중했다.
내가 이번 과제를 진행하면서 구현한 기능은 다음과 같다.
@
포함 시 로그인 버튼 활성화 및 색상 변경@keyframes
를 이용하여 로그인 페이지의 fade-in/out 이미지 구현
위코드에서는 스마트폰 이미지 말고 로그인 input 부분 정도만 구현하면 되었었는데 하다 보니 욕심이 생겨서 인스타그램의 로그인 페이지와 최대한 비슷하게 만들어보고 싶어졌다. 초반에는 인스타그램의 로그인 페이지와 최대한 같게 해보려고 노력했으나 시간이 지날수록 비중이 더 큰 작업에 집중하게 되어서 겉모습만이라도 100% 똑같은 로그인 페이지를 만들지는 못했다.
로그인 페이지를 만들면서 개발자 도구에서 인스타그램이 실제로 사용한 이미지 파일들을 볼 수 있었다.
위와 같은 png파일을 보고 어떻게 사용하면 좋을지 고민하고 있을 때 몇몇 동기들은 그냥 필요한 부분의 이미지를 잘라서 쓰거나 잘라져있는 이미지를 사용했다. 처음에는 그냥 동기들처럼 필요한 부분만 잘라서 써야 하나 고민하고 있었을 때 백그라운드 이미지로 넣어서 필요한 부분만 보이게 해서 쓰면 된다는 사실을 알게 되었고 로그인 페이지의 페이스북 로고와 인스타그램 로고를 위에 보이는 png 파일을 이용해서 실제 인스타그램과 같은 방식으로 이미지를 보여줄 수 있게 되었다.
그리고 개인적으로 가장 마음에 드는 부분은 스마트폰 속에 이미지가 움직이는 것이다.
@keyframes
를 이용하여 fade in/out 효과를 준 것으로 상당히 만족할만한 결과물이 나왔다. 아래의 gif 이미지는 그 결과물이다.
위의 이미지에서 볼 수 있듯이 아이디에 @
이 포함되고 비밀번호가 6자 이상이면 로그인 버튼이 활성화되어서 로그인 버튼을 클릭하거나 엔터키를 입력하면 메인 페이지로 이동할 수 있다.
@media screen and (max-width: 875px) {
.leftContainer {
display: none;
}
.navBottom {
@include flexColumn;
}
.navBottom ul {
max-width: 360px;
justify-content: center;
margin: 0 auto;
text-align: center;
}
}
처음으로 백엔드와 통신해본 기념비적인 코드
비밀번호가 틀리거나 양식에 맞지 않을 경우에 대처하지 않지만 콘솔에 찍히는 200 OK
는 내 안에 있는 무언가에게도 OK 신호를 쏴주었다.
메인 페이지에서는 Nav bar, Story, Feed, Suggestions 4가지 부분으로 나누어진다.
메인 페이지에서 필수 구현 사항은 댓글 달기였고, nav 바와 추천 탭은 겉모습만 만들면 됐었고, 스토리 부분은 없어도 되는 부분이었다.
메인 페이지도 로그인 페이지와 마찬가지로 브라우저 가로 길이에 반응한다.
Nav 바의 검색창은 실제 인스타그램처럼 구현하려고 html 구조를 나눴었지만 기능은 시간 관계상 구현하지 않고 겉모습만 똑같이 만들었다. 다음 1차나 2차 프로젝트에서 비슷한 효과가 있다면 꼭 구현해보고 싶은 부분 중 하나이다.
Story 부분에서는 나중에 백엔드와 통신할 경우를 대비해서 Mock 데이터에 따라 스토리에 보여지는 정보가 늘어날 수 있도록 map()
함수를 썼다.
Story.js (부모)
StoryItems.js (자식)
부모에서 자식 컴포넌트로 데이터를 넘겨줘야 했는데 이 과정을 진행하기 위해서 컴포넌트 간 데이터가 어떻게 이동해야 하는지 먼저 이해가 필요했다. 위코드의 노션 페이지도 보고, 다른 개발자가 작성한 블로그 글도 보면서 이해를 했고 나에게 가장 도움이 크게 되었던 블로그를 보고 번역 정리한 글은 이 기능을 구현할 당시 작성했다. 부모에서 자식 컴포넌트로 데이터를 넘겨주는 건 간단해서 이해하는 데에 어려움은 없었다.
코드 리뷰를 받을 때 멘토님이 destructuring을 한번 해보라고 하셔서 적용해 보았는데 가독성도 높아지고 반복을 줄일 수 있어서 코딩을 하면서도 만족스러웠고 앞으로도 자주 써야겠다고 생각한다!
이 부분은 mock data와 map() 함수를 적용하진 않았고, 겉으로 보이는 부분만 비슷하게 만들어 두었다.
추천 목록 밑에 작게 뜨는 이 목록이 조금 까다로웠던 거로 기억한다.
링크 사이사이에 점이 찍혀 있었는데 마우스로 긁어보았을 때, 문자가 아니어서 복사가 되지 않았고, 개발자 도구를 열어 보고 after
를 사용했다는 것을 알 수 있었다.
위와 같이 작성하면 li
태그 사이에 점이 생기고 마지막 li
태그의 뒤에는 점이 생기지 않게 할 수 있다.
피드가 뜨는 부분을 HTML과 CSS로만 구현했을 때는 피드 한 개를 만들기 위해서 같은 코드를 반복적으로 넣어야 했고, 피드의 수만큼 태그의 수도 많아져서 가독성이 떨어졌었다. 하지만 react에서는 컴포넌트로 만들어두면 바뀔 부분만 부모 컴포넌트에서 자식 컴포넌트로 넘겨주기만 하면 간단히 해결이 되는 문제이기 때문에 신기하기도 했고 재미도 있었던 부분이다. 아직 백엔드와는 로그인만 fetch
를 써서 해본 게 다였기 때문에 Feed는 object
로 mock data를 만들어서 map()
함수를 적용하였다.
this.props.userInfo
는 Main.js>Feeds.js>Feed.js에 넘겨주는 데이터로, 댓글 입력 시 작성자의 아이디를 받아오게 된다.
댓글의 개수와 좋아요를 받은 수는 따로 리스트의 길이를 구하거나 카운트를 해 놓지 않아서 실제로 유동적으로 움직이지는 않지만 백엔드에서 데이터만 넘겨준다면 쉽게 적용 가능한 부분이라고 생각한다. 👀
(좋아요를 누른 친구의 이름이 뜨는 경우와 뜨지 않는 경우, 피드가 이미지 여러 개일 경우, 동영상일 경우도 대처를 해야 하지만 이번 프로젝트의 목표와는 거리가 있어서 구현하지 않았다. 🙈)
대부분의 동기들은 각종 버튼을 이미지 파일로 구현했다. 하지만 실제로 인스타그램에서 개발자 도구를 열어 확인해보면 svg
를 이용한 것을 확인할 수 있다. svg
는 Scalable Vector Graphics 라고 한다. 이름에서부터 알 수 있듯이 크기의 조절이 가능하고 확대를 해도 깨지지 않는다는 장점이 있고 파일로 저장했을 때 용량이 작다는 장점도 있다. 그래서 버튼의 이미지를 캡처하거나 다른 곳에서 가져다 쓰기보다는 개발자 도구에서 보여지는 그대로를 가져와서 써보고 싶다고 생각했다. React 없이 DOM을 할 때는 svg를 createElement
로 만들어서 댓글을 새로 입력 시 원하는 부모 태그에 append
시키려고 시도했었는데 저 방법은 svg라는 이름을 가진 일반 태그를 만들 뿐이어서 제대로 할 수 없었고 createElementNS
를 사용하여 해결한 기억이 있다.
요로케..🐷
하지만! 리액트에서는 위의 과정이 필요가 없고 그냥 HTML 태그를 작성하듯이 적어주기만 하면 된다. 🙌🏻
위와 같이 작성하여 부모 태그의 state
에서 clicked
의 Boolean 값을 읽어와서 클릭 시 하트의 모양과 색깔을 바뀌게 하였다. 클래스 이름도 따로 바뀌게 한 이유는 클릭 시 하트에 움직임을 주고 싶었기 때문이다.
위의 이미지는 인스타그램에서 좋아요 버튼을 클릭했을 때의 모습이다. 좋아요를 취소하려고 다시 눌러도 하트가 튀어 오르는 모습을 볼 수 있다.
개인적으로 하트의 빨간불(?)이 꺼질 때는 아무런 효과도 없었으면 더 좋지 않을까? 하는 마음에 누를 때만 하트가 튀도록 구현해보았다.
피드와 댓글의 하트에 동일한 효과를 적용했다. 아래와 같이 몇 줄 안되는 CSS 효과로 간단히 구현 가능하다.
댓글을 작성할 때도 map()
함수를 사용하여 추가했고, 다음과 같은 로직으로 작동한다
textarea(onChange
) -> setState
(댓글내용) -> 빈 배열에 object 형태로 {key:(댓글내용)} push
-> 이 배열로 map()
함수 사용 -> ul
태그의 자식 요소로 li
컴포넌트 추가
map()
함수 사용 부분은 앞서 올린 코드와 매우 유사하기 때문에 댓글 작성 부분의 코드는 생략하겠다.
댓글 작성 기능을 구현하면서 아쉬웠던 부분이 있었다. 댓글 입력 시 버튼을 클릭하면 아무런 문제 없이 잘 작동하지만 크롬의 버그인지는 확실하지 않지만 작성하던 문자의 마지막 글자가 한글이면 keyUP
이벤트에 작동해야 함에도 불구하고 한글은 keyDown
시 댓글이 입력이 되어버리는 문제가 있다. 댓글이 입력되고 나서 비어져있어야 하는 댓글 입력창에는 개행 1줄이 들어가 있는 현상도 발생한다. 댓글 입력창 부분을 input
태그로 바꾸고 keyPress
로 바꾸면 해결이 된다고는 하는데 인스타그램놈들은 textarea
를 썻고, 나도 똑같이 만들어보고 싶었다. 하지만 간단해 보였던 이 기능은 의외로 구현하기가 까다로웠다.
처음 1주간 Vanilla JS를 사용하여 전체적인 구조와 흐름을 파악했고, 왜 React를 쓰면 좋은지, 어떠한 필요에 의해 React가 등장했고, 많은 개발자들에게 사랑을 받고 있는지 몸소 느낄 수 있는 기회였다. 태그와 클래스명이 점점 많아지면서 CSS에서는 작명에 쓰는 시간과 고민이 많았었는데 SASS를 사용하면서 nesting을 하게 되고, 변수도 선언하면서 그런 고민과 불편함이 해소되었다.
처음에 1주간 Vanilla JS를 사용할 때는 혼자서 진행했는데 React와 SASS를 사용하기 시작하면서 비록 각자가 구현하는 로그인 페이지와 메인 페이지는 나누어져 있었지만 하나의 컴포넌트와 공용 scss파일을 써보면서 팀 프로젝트처럼 팀원과 Git도 사용하고 팀웍에 대해 배울 수 있는 소중한 시간이었다고 생각한다.