JavaScript
를 통해서 구현했던 인스타그램을 다시 React
를 통해서 구현하는 프로젝트를 하게 됐다. 기존에 DOM
을 조작해서 넣었던 기능들을 state
와 props
를 이용해서 구현하려다 보니 어려운 점도 많았는데, 돌이켜보면 어째서 React
를 써야하는지 느끼게 된 프로젝트이기도 했다. 초면이었던 React
와 조금은 친해지게 된 위스타그램
에 대해 정리해본다.
2021.08.23 ~ 2021.08.26
- HTML / SASS
- JavaScript(ES6 + )
- React
Login
: 아이디, 패스워드 유효성 검사 로직 Login
: 백엔드 API를 통한 회원가입 & 로그인 구현 Main
: Mock data 통한 피드 및 댓글 구현 Main
: 댓글 추가 & 삭제 구현 Nav
: 검색어 자동완성 기능 구현 Nav
: 프로필 메뉴 토글 기능 구현 댓글 추가 기능
댓글 삭제 & 좋아요 기능
아이디 검색 기능
프로필 메뉴 토글 기능
UI
를 위한 자바스크립트 라이브러리선언적
특징을 가지고 있는 라이브러리UI
단위 컴포넌트
리액트
관련 세션을 듣고 생각보다 익숙한 모습에 친근하게 느껴졌다. JSX
는 HTML
태그와 모습이 비슷했고 class
가 낯선 것만 빼면 JavaScript
니까 금방 할 수 있을거라 굳게 믿었다.
하지만... 세션 후에 JS
로 구했했던 코드들을 CRA
폴더에 옮기고 화면을 그리자 당황스러움이 느껴졌다. 심지어, 첫 협업으로 같은 폴더를 공유하며 진행해야하다보니 함부로 파일들을 수정할 수 없었는데 이로 인해서 많은 어려움이 있었다.
특히 Nav
부분을 맡아서 진행하다가 나의 허술함을 강력 어필하게 됐다. master
가 아닌 개인 branch
에서 nav
관련 branch
를 생성했다가 작업물이 사라지는 경험을 하기도 하고 여러 번의 수정으로 팀원들에게 반복되는 사과를 하기도 했다.
무엇보다... state
와 props
를 사용해서 기능들을 구현하는 방법은 사고의 방향이 다르게 느껴져서 혼란스러웠다. 하지만, 결국에는 React
가 얼마나 좋은 것인지 알게 되었다.
이번 주 세션 중에서 가장 재밌었던 순간을 뽑자면 바로 백엔드와 연결을 해보는 시간이 아니었나 싶다.
// 회원가입 코드
handleSignUp = event => {
fetch('${baseUrl}/users/sign-up', {
method: 'POST',
body: JSON.stringify({
name: '하루',
email: this.state.id,
password: this.state.password,
phone_number: '010-1111-2222',
date_of_birth: '2001-01-02',
}),
})
.then(result => result.json())
.then(result => console.log(result));
};
프론트엔드의 경우에는 간단한 유효성 검사 정도의 로직만 구현을 했다보니 세션 후에 실습 시간에 바로 코드를 작성해야 했다. 백엔드 페어로 지정되신 우주님에게 key
값과 엔드포인트
에 대해서 물은 후에 바로 코드를 작성했다. 다행스럽게도 금방 400 에러 를 만날 수 있었고 연결은 됐다!! 하며 즐거워했다.
이 과정에서 400 에러 를 자주 봤었는데 이유는 우주님이 작성하신 유효성 검사에 대해서 정확하게 묻지 않고 진행하다보니 생긴 일이었다. 어떤 값들을 입력해야하는지 정확히 의견을 나누고 진행하니 곧 CREATE
라는 메세지를 받을 수 있었다. 나도 모르게 환호성을 질렀던 기억이 난다. 백엔드 최고!
// 로그인 기능
handleLogin = event => {
fetch('${baseUrl}/users/login', {
method: 'POST',
body: JSON.stringify({
email: this.state.id,
password: this.state.password,
}),
})
.then(result => result.json())
.then(result => {
result.TOKEN
? this.props.history.push('/main-cheoljin')
: alert('아이디와 비밀번호를 맞게 작성해주세요');
});
};
이제 회원가입 한 아이디와 비밀번호를 입력해서 로그인만 시키면 됐다. 엔드 포인트 주소를 바꿔서 입력해 준 후에 body
에 관련된 내용을 담아 보냈더니 진짜로 토큰을 받아볼 수 있었다. 세션으로 듣기만 했던 토큰을 실제로 확인하니 매우 신기했다.
알아먹을 수 없는 토큰이라는 존재가 이렇게 기쁜 존재인지 몰랐다.
리액트를 진행하면서 가장 좋았던 점은 한 눈에 보기가 불편했던 코드가 컴포넌트
를 나눌 수록 매우 보기 편해진다는 점이었다.
import React, { Component } from 'react';
import Nav from '../../../components/Nav/Nav';
import Aside from './Aside/Aside';
import Feed from './Feed/Feed';
import './Main.scss';
class MainCheoljin extends Component {
state = {
feeds: [],
};
render() {
return (
<div className="main-cheoljin">
<Nav />
<main className="main">
<div className="main__container">
<section className="main__feeds">
{this.state.feeds.map(feed => (
<Feed key={feed.id} feed={feed} comments={feed.comments} />
))}
</section>
<Aside />
</div>
</main>
</div>
);
}
}
export default MainCheoljin;
기존에는 매우 길어서 원하는 부분을 찾기 위해서 cmd
+ F
가 필수였는데 지금은 한 눈에 어떤 구조로 만들어져 있는지 볼 수 있게 되었다. 처음에는 기존의 코드를 컴포넌트
로 바꾼다는 점이 어렵게 느껴졌는데 시간이 갈 수록 컴포넌트
들을 더 나누면서 즐거웠다.
리액트
를 배우고 적용하면서 정말 기뻤던 부분은 바로 Array.map()
와 컴포넌트
가 시너지를 만들어 하드코딩을 정말 많이 줄일 수 있게 되었다는 점이었다. 이전에는 피드를 여러개 만들고 싶거나 댓글을 여러개 만들고 싶은 경우에 하나씩 하드코딩하면서 만들어야하는 불편함이 있었다. 이는 코드 역시 쓸데없이 길게 만들어서 가독성도 많이 헤치는 점이었다.
<section className="main__feeds">
{this.state.feeds.map(feed => (
<Feed key={feed.id} feed={feed} comments={feed.comments} />
))}
</section>
이렇게 컴포넌트
를 만들고 Array.map()
을 이용하면 짧은 코드로도 여러 개의 피드나 댓글을 만들 수 있다. 또한, JavaScript
를 이용해서 DOM
에 이벤트 리스너를 등록하고 함수들을 추가했을 때는 한 개의 피드에서만 정상적으로 동작하는 단점이 있었는데 리액트에서는 컴포넌트
를 통해서 자연스럽게 모든 피드에서 동작하도록 할 수 있었다.
리액트
의 장점에 푹 빠진 것 같기도 하지만, 여전히 어려운 점은 많다. main
에서 모든 state
를 관리하면서 댓글 추가 & 삭제 기능의 로직이 복잡한 것을 바꿔보기 위해서 feed
에서 자신의 관련된 상태만 받아서 이용할 수 있도록 변경하였는데 이 과정에서 여러 오류를 겪었다. 컴포넌트가 렌더링 되는 과정에 대해서 정확한 이해가 부족하다 보니 생긴 일이었다.
constructor
-> render()
-> componentDidMount()
순으로 발생한다는 점은 겪어보면서 느낄 수 있던 점이었다. 그 과정에서 Optional Chaining
이나 componentWillMount
등에 대해서도 공부해 볼 수 있었다. 리액트에 대해서 공부할 점이 앞으로도 정말 많을 것 같다는 생각이 든다.
역으로 검색 기능 같은 경우에는 복잡했던 코드가 간단해지기도 했다.
const searchResult = searchValue
? searchList.filter(list => list.id.indexOf(searchValue) === 0)
: PREVIEW_DATA;
만약 사용자가 검색어를 입력한다면 그거에 맞는 데이터만을 전달하여 SearchItem
을 Array.map()
을 통하여 컴포넌트를 그려낼 수 있도록 하고 아니라면 PREVIEW_DATA(이전 검색)
을 보여주도록 했다. 전에 DOM
을 통해서 구현했던 것에 비해 훨씬 간단하게 구현할 수 있어서 놀라웠다.
우선, 여러가지 일들이 많았던 기간 동안 좌절하지 않고 끈기 있게 리액트에게 말을 걸었던 나에게 칭찬을 해주고 싶다. 쉽지도 않았고 정말 다사다난했지만 새로운 기능에 두려움보다는 호기심으로 다가가기 위해서 노력했다.
무엇보다, 여러 동기분들의 코드를 보면서 문제들이 생겼을 때 해결해보기 위해서 고민했던 시간들이 있어서 좋았다고 생각한다. 다른 사람의 코드를 보는 연습, 문제가 생겼을 때 천천히 디버깅 하는 연습이 되었다고 생각한다. 다소 많은 console.log()
를 찍으며 귀찮게 해드리지는 않았나 싶기는 하지만 같이 문제를 해결해나가는 즐거운 시간이었다고 믿는다.
여전히, 코드를 정리해나가고 불필요한 부분을 줄이는 연습은 부족하다고 생각이 든다. 또, 공식문서를 더 많이 읽으면서 항상 최선인지에 대해서 고민하는 연습도 필요하다고 느낀다. 원하는 만큼 기능들을 구현해보기는 했지만 그 과정에서 불필요한 코드가 남기도 하고 다소 부적절한 방법으로 코드를 작성하기도 했다. 이런 부분들은 앞으로 계속 고쳐나가야 하는 점이라고 생각한다.
누가 봐도 읽기 편한 코드, 이해하기 좋은 코드를 작성하도록 노력하자.
같은 동기분들에게 가끔 질문을 받으면 무언가 도움이 될 수 있는 것 같아 기쁘다. 비슷한 문제를 겪었고 경험했기 때문에 적절한 도움을 드릴 수 있는 경우가 대부분이다. 나 또한, 어려운 문제가 있을 때 질문 하나로 해결이 되는 경우도 정말 많다.
혼자서 진행했다면 어렵고 힘들었을 이 시간들을 함께 걸어나갈 수 있는 동기들이 있어서 정말 좋다. 특히, 나의 열정 정도는 작아보이게 만들만큼 열심히 자신의 길을 걸어나가는 동기님들이 있어서 뒤쳐지지 않기 위해 한 발, 두 발 더 나갈 수 있다.
지금의 내가 옆에서 함께 일하고 싶은 개발자로서 성장하고 있는지는 아직 잘 모르겠다. 하지만, 꼭... 옆에서 함께하고 싶은 개발자가 되도록 더욱 단단하게 걸어보려고 한다. 이 시기를 함께 해주는 24기 동기분들 모두에게 정말 감사하다.
이렇게 돌아보니 한 주 사이에 정말 많은 걸 배웠었네요ㅠㅠ다음주 1차 프로젝트도 힘내서 뿌셔버립시다^0^!