Westagram - React
위코드에서 한달간의 생활
위코드에 와서 생활한지도 어언 한달이 지났다. 한달동안 정말 많은 일들이 있었다. 동기들과 처음만나고 어색했지만 지금은 편해진 동기들도 있다. 한달간의 생활동안 동기분들에게 정말 많이 배웠던 것 같다. 모르는건 이렇게도 해보고 저렇게도 해보았지만 되지 않아서 좌절했던 순간이 많았는데 동기분들에게 물어도보고 스스로 찾아도 보면서 리액트를 활용한 westagram with react project가 끝이났다. 모든 순간순간들이 기억이 난다고는 말할 수 없지만 하나하나 찬찬히 프로젝트의 순간순간들을 회고해보면서 다시한번 정리해보자.
초기세팅
팀원들과 공동작업을 한다고 가정을 하고 프로젝트를 진행하였다. 물론 각자 로그인과 메인페이지를 만들지만 깃으로 작업내용들을 관리하고 깃허브로 각자의 진행상황과 구현내용들을 올려보면서 현업에서하는 분위기를 느낄 수 있었다. 또한 초기세팅 과정에서 여러협의를 거치지 않으면 서로의 페이지에서 문제가 발생할 수도 있기에 (특히, CSS) 앞으로 프로젝트를 진행하게 된다면 이부분에서 디테일하게 정해야 할 것 같다.
로그인페이지
로그인페이지는 정말 험난했다. 원래는 처음에 자바스크립트로 구현한것들을 리액트로 넘겨오는 과정에서 태그들의 이름들을 모두 리팩토링하여 진행하였다. 실제로 인스타그램의 로그인페이지를 하나하나 다 뜯어보았을때 너무나 많은 div
태그들이 걸려있어 똑같이 해보겠다고 따라했었는데 많이 지저분하고 알아보는게 너무나 힘들었다. 완전히 똑같이 따라하는게 막상 내가 코딩을 기르는 실력에 있어서 많은 도움이 될까? 라는 생각도 들었다. 그렇기에 넘겨오기전에 하나하나 이름부터 잘 정리해서 가져와 진행하였고 훨씬 수월하게 진행하였다.
로그인페이지의 기본적인 틀
return (
<div className="loginContainer">
<div className="loginForm">
<h1 className="formTitle">Westagram</h1>
<form className="loginIdPwBtn">
<input
id="inputId"
type="text"
placeholder="Phone number, username or email"
onChange={handleIdInput}
onKeyUp={isPassedLogin}
onKeyPress={isLoginValid ? handleKeyPress : null}
/>
<input
id="inputPw"
type="password"
placeholder="Password"
onChange={handlePwInput}
onKeyUp={isPassedLogin}
onKeyPress={isLoginValid ? handleKeyPress : null}
/>
<button
id={isLoginValid ? 'loginBtnActive' : 'loginBtnDisable'}
onClick={onClick}
disabled={!isLoginValid}
type="button"
>
Log In
</button>
</form>
<div className="formOr">
<h4 className="orText">OR</h4>
</div>
<div className="formLinkBtn">
<a href="https://google.com/">
<i className="fab fa-facebook-square" />
</a>
<a className="linkBtn1" href="https://www.facebook.com/">
Log in with Facebook
</a>
</div>
<a className="formForgotPw" href="https://www.facebook.com/">
Forgot password?
</a>
</div>
</div>
);
로그인페이지의 기능구현
1. 쓸데없는 state는 최대한 지양
const [isActive, setIsActive] = useState(false);
const isPassedLogin = () => {
return idInput.includes('@') && pwInput.length > 4
? setIsActive(true)
: setIsActive(false);
};
해당 코드는 버튼의 활성화 비활성화와 관련된 선언과 함수였다. 하지만 isActive는 따로 지정할 필요가 없었다.
const isLoginValid = idInput.includes('@') && pwInput.length > 4;
const isPassedLogin = () => {
return isLoginValid;
};
위의 코드로 대체가 될 수 있기 때문이다. 굳이 active가 없어도 이 조건만으로 대체가 가능했기 때문에 코드를 줄일 수 있었다.
2. hooks 선언부는 유지보수 및 가독성을 위해 컴포넌트 최상단에서 모아서 관리
내 코드들은 선언부와 함수들이 마구 섞여있었다. 나는 선언과 함수를 위-아래 이런식으로 관리해서 선언을 본 후 바로 함수를 보고 이해하겠다. 이런 느낌으로 진행하였는데 코드가 길어지고 복잡해지면 유지보수가 힘들어지기 때문에 최상단에서 관리하는 습관을 길들이자.
3. 임포트 과정에서 여러줄로 나누어 적지말기 필요없는 scss파일 지양
import React, { useState } from 'react';
이렇게 한줄로 처리할 수 있는 것들은 한줄로 처리하자.
import './reset.scss';
import './common.scss';
공통의 부분은 Index에서만 임포트 하면 끝.
4. 기능 구현
const [idInput, setIdInput] = useState('');
const [pwInput, setPwInput] = useState('');
const isLoginValid = idInput.includes('@') && pwInput.length > 4;
const navigate = useNavigate();
const handleIdInput = event => {
setIdInput(event.target.value);
};
const handlePwInput = event => {
setPwInput(event.target.value);
};
const isPassedLogin = () => {
return isLoginValid;
};
const handleKeyPress = e => {
if (e.key === 'Enter') {
goToMain();
}
};
const goToMain = () => {
navigate('/main-jihong');
};
const onClick = () => {
goToMain();
};
-
Id와 Pw의 input값을 변화를 감지하도록 useState 활용
-
keyUp, keyPress 이벤트를 통해 엔터키를 활용한 페이지 전환
-
useNavigate 활용을 통해 페이자간의 전환 / Spa의 특성에서 꼭 알아둬야할것
-
삼항 연사자를 활용해 버튼의 활성화 구현
5. 기능구현시 렌더링된 이미지
메인페이지
메인페이지 정말 너무 너무 어려웠다. 댓글을 추가삭제 / 좋아요 버튼 활성화 등 간단한 작업들이 이렇게 어렵다니 개발자들이 새삼 대단해보이면서도 스스로한테 자책도 많이 해보았다.
메인페이지의 기본적인 틀
메인페이지는 컴포넌트를 만들어 볼 수 있는 좋은 기회였다. 레이아웃을 보면 Nav / Main으로 나누어 질수 있고 이렇게 메인페이지 안에 모든걸 다 넣었다. 하지만 컴포턴트의 재사용을 배우면서 Main은 Feed / Aside 부분으로 나누어 질 수 있고 이렇게 컴포넌트를 사용해서 만들면 유지보수가 쉽다고 배웠기 때문에 나누어 보았다.
메인페이지의 구성
<>
<Nav />
<div className="container">
<main className="main">
<div className="feedBox">
{feedList.map((feed, idx) => {
return (
<Feed
userName={feed.userName}
userImg={feed.userImg}
feedImg={feed.feedImg}
key={idx}
description={feed.description}
userComments={feed.comments}
/>
);
})}
</div>
<Aside />
</main>
</div>
</>
메인페이지의 기능구현
1. 댓글 추가 및 삭제 및 좋아요 기능
공부한 내용 : map, filter
기존 작업 과정에선 하드코딩을 했기때문에 피드가 하나만 만들어져 있었고Main - 댓글창의 구조로 바로 구현이 가능했었다. 하지만 피드를 컴포넌트로 만든다음 기능을 구현하는 과정에서는 중간단계를 하나 놓아주어야 했다. 따라서 메인에서 피드부분으로 props를 전달하고 피드부분에서 댓글창으로 props를 내려줘야 했고 이부분에서 props에 대해 정말 많이 헷갈리고 많은 부딪힘이 있었다. 아직까지도 완전히 이해했다기보다는 점차 만들면서 계속 이해나는 과정이 필요할것 같다.
1.1 피드부분의 로직
const [comments, setComments] = useState(userComments);
const [commentInput, setCommentInput] = useState('');
const [isLiked, setIsLiked] = useState(false);
const isLikeClick = () => {
setIsLiked(!isLiked);
};
const onChange = event => setCommentInput(event.target.value);
const onSubmit = event => {
event.preventDefault();
setComments([
...comments,
{
userName: 'guest',
comment: commentInput,
id: Math.ceil(Math.random() * 100),
},
]);
setCommentInput('');
};
<div className="userComment">
<div className="comment">
{comments?.map((comment, idx) => {
return (
<CommentItem
userName={comment.userName}
id={comment.id}
key={idx}
comment={comment}
comments={comments}
setComments={setComments}
/>
);
})}
</div>
</div>
<form className="feedComment" onSubmit={onSubmit}>
<div className="writeComment">
<img className="profileImg2" src={userImg} alt="프로필" />
<input
className="inputComment"
onChange={onChange}
value={commentInput}
type="text"
placeholder="댓글 달기..."
/>
<button className="inputBtn">게시</button>
</div>
</form>
1.2 댓글창 하나의 로직
const CommentItem = ({
comment,
index,
id,
setComments,
comments,
userName,
}) => {
const [isLiked, setIsLiked] = useState(comment.isLike);
const isLikeClick = () => {
setIsLiked(!isLiked);
};
const deleteComment = id => {
setComments(comments.filter(user => user.id !== id));
};
return (
<div>
<li key={index}>
<span>{userName}</span>
{comment.comment}
<button className="likeBtn" onClick={isLikeClick}>
<i className={`${isLiked ? 'fas' : 'far'} fa-heart`} />
</button>
<button className="deleteBtn" onClick={() => deleteComment(id)}>
X
</button>
</li>
</div>
);
};
2. 목데이터와 상수데이터의 활용
공부한 내용 : useEffect와 fetch 데이터 활용
현업에서는 프론트와 백엔드간의 협업을 통해 페이지가 사용자와 인터렉티브하게 움직인다. 그렇지만 작업속도간의 차이가 나서 기능을 테스트해보고 싶다면 무엇을 사용할까? 목데이터 와 상수데이터를 활용한다. 목데이터는 내가 구현하고 싶은 기능을 하드코딩이 아닌 데이터와 연관지어 테스트 해보고 싶을때 사용한다고 배웠다. 그리고 useEffect는 리액트의 렌더링 과정에서 가져와야하는 정보들을 렌더링이 이루어질때마다 가져와지는 것이 아닌 첫 렌더링 될때만 가져오는 것을 뜻한다. useEffect를 사용하지 않으면 정보들이 많아질수록 서버에 많은 부하가 걸릴 수 있다.
useEffect(() => {
fetch('/data/feedJihongData.json', {
method: 'GET',
})
.then(res => res.json())
.then(data => {
setFeedList(data);
});
}, []);
만들어본 목데이터
후기
구현 목표 및 구현사항 설명 요약
이렇게 프로젝트의 회고를 해보면서 스스로가 다시한번 어떠한 로직을 활용해 기능을 구현했는지 파악하고 '이때 이런걸 썼구나' / '이때는 이런걸 활용했네', '아 이때 진짜 안되서 고생했네' 등등 정신없이 지나오는 순간들을 회상해보게 되는 계기가 되어서 새로웠다. 하지만 프로젝트가 끝나고 나서 전체를 회고하려는 습관보다는 좀 앞으로는 중간중간 회고하는 습관을 가져가면서 좀 더 디테일하게 써봐야겠다.
Author And Source
이 문제에 관하여(Westagram - React), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jujihong2/Westagram-React저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)