Westagram Cloning Project
개발 기간 : 6.29~ 7.19 (2주, 자바스크립트) , 7.13~7.19 (1주 리액트)
개발 목적 : 전세계 가장 영향력있는 소셜 미디어 플랫폼인 인스타그램 클로닝
구현 기능 :
1) (로그인페이지) 아이디,비밀번호 입력 시 로그인 버튼 색깔 변경
2) (로그인페이지) 미리 설정한 아이디, 비밀번호 입력해야 메인 페이지 이동 가능
3) (로그인페이지) 비밀번호 틀릴 시 '비밀번호 틀렸습니다'
4) (메인 페이지) 댓글 기능 구현
5) (메인 페이지) 댓글 삭제 기능 구현
class Login extends React.Component {
constructor() {
super();
this.state = {
backgroundColor : "",
id : "",
password : "",
ready : false,
myId : "djaxornwkd12@gmail.com",
myPassword :"qudtn12",
passwordError : false
}
}
inputIdValue = (e) => {
this.setState({
id : e.target.value
})
}
inputPasswordValue = (e) => {
this.setState({
password : e.target.value,
ready : e.target.value.length>5&&this.state.id.includes('@') ? true : false
})
}
1)
inputIdValue
,inputPasswordValue
라는 변수에 호출 시 동작되는 함수를 담았고 setState으로 id값,password값 인풋 입력 시 state값 변경될 수 있게 만들었다
2) 패스워드에는 id값과 password값 특정 조건 충족시 state의 ready 값의 밸류를 트루로 바꿔준다
그래서 밑의<button className={this.state.ready ? "login ready" : "login btn"}
에 의해 button의 클래스네임 변경되어 바뀐 css가 적용되게 된다.
✅ 위와같이 className에 바로 삼항연산자 쓰는 방식은 자주 쓰인다!
goToMainPage = (e)=> {
const { id,password,myId,myPassword } = this.state
if(id=== myId && password === myPassword) {
this.props.history.push('/main-byeongsoo')
}
else {
this.setState({
passwordError : true
})
}
1)
destructuring
으로this.state.
라고 일일이 써주는 것을 간결하게 해준다 참고사이트
2)this.props.history.push
로 페이지 이동
3) input에 입력한 id값과 password값이 미리 state에 설정한 myId, myPassword값아 일치 시 메인 페이지로 이동
4) 틀릴 시passwordError
state 키값 밸류 true로 변경 -><div className={this.state.passwordError ? "error":"noError"}>잘못된 비밀번호입니다. 다시 확인하세요</div>
에 의해 className변경hidden
되어 있던 visibilityvisible
로 변경
✅ visibility : hidden or visible로 특정 조건일 때만 보이게 만들 수있다
.noError {
visibility: hidden;
}
.error {
visibility: visible;
font-size: 15px;
font-weight: bold;
color : red;
}
fetch("http://10.58.0.223:8000/user/signin", {
method :"POST",
body : JSON.stringify({
email:this.state.id,
password: this.state.password
})
})
.then(res => res.json()) // JSON body -> JS
.then(res => sessionStorage.setItem("access_token", res.access_token))
}
render() {
return (
<div className="Login_BS">
<div className="Wrapper">
<div className="logo">
<img src = "/images/byeongsoolee/logo_text.png" alt="메인로고" />
</div>
<div className="InfoBox">
<input type="text" value={this.state.id} onChange={this.inputIdValue} className="login contents id" placeholder="전화번호, 사용자 이름 또는 이메일" />
<input type="password" value={this.state.password} onChange={this.inputPasswordValue} className="login contents pwd" placeholder="비밀번호" />
<button className={this.state.ready ? "login ready" : "login btn"}
onClick={this.goToMainPage}>로그인</button>
</div>
<div className={this.state.passwordError ? "error":"noError"}>잘못된 비밀번호입니다. 다시 확인하세요</div>
<div className="forgetPwd">비밀번호를 잊으셨나요?</div>
</div>
</div>
);
}
}
export default Login;
import React from "react";
import "./Feed.scss";
class Feed extends React.Component {
constructor(props) {
super();
this.state = {
comments: [
"tottenham_official wow Jisung Park is my favorite player!",
"real_madrid_official Jisung Park is a living lenged",
],
typeComment: "",
};
}
textChange = (e) => {
this.setState({
typeComment: e.target.value,
});
};
add = () => {
const { comments, typeComment } = this.state;
typeComment.length !== 0 &&
this.setState({
comments: comments.concat(`hm_son7 ` + typeComment),
typeComment: "",
});
};
1) add라는 변수만 어떤 동작을하는 함수인 지 파악하기 힘들다->✅ 함수명은 그것만 봐서 알 수 있는 적절한 이름으로 지어야한다
2) add라는 함수로 댓글 입력 시 추가되는 기능 구현을 했다✌️ state으로 정의했던comment
배열에concat
method로 내가 입력한 것(typeComment
)을 붙여주는 방식으로 구현했다.
handleKeyPress = (e) => {
e.keyCode === 13 && this.add();
};
버튼에
onClick
을 줬지만 인풋에서 엔터 시 댓글이 추가될 수 있도록onKeyUp={this.handleKeyPress}
를 걸었다! 👍
handleDelete = (index) => {
const tempArr = this.state.comments.slice(0, index);
const afterDeleteArr = this.state.comments.slice(index + 1);
this.setState({
comments: [...tempArr, ...afterDeleteArr],
});
};
제일 힘들게 작성한 코드 😂 사실 준식님,종택님의 도움으로 완성한 코드지만 제일 애착이 큰 코드
1)slice
의 특성을 활용해 해당 댓글 (index)만 제외 그 전 댓글들과 그 후 댓글들을 분리했고
spread operator
를 활용해 state의 comments의 배열 값이 바뀌게 만들었다
render() {
const commentList = this.state.comments.map((typeComment, index) => {
return (
<li className="replyList" key={index}>
{typeComment}
<span className="imgList">
<span onClick={() => this.handleDelete(index)}>삭제</span>
</span>
</li>
);
});
return (
<div className="Feed_BS">
<div className="feedsContainer">
<div className="header">
<div className="profile">
<img
alt="맨유 프로필"
src="https://scontent-gmp1-1.cdninstagram.com/v/t51.2885-19/s320x320/95389054_555222165374068_542779107667083264_n.jpg?_nc_ht=scontent-gmp1-1.cdninstagram.com&_nc_ohc=m6OgKSZDdncAX83Bmgk&oh=ba627dce6632eb1cd73943c1624731d0&oe=5F2645D0"
/>
<p>manchester_united</p>
</div>
<img
alt="..."
src="https://s3.ap-northeast-2.amazonaws.com/cdn.wecode.co.kr/bearu/more.png"
/>
</div>
<div className="feedPic">
<img
alt="박지성 사진"
src="https://scontent-gmp1-1.cdninstagram.com/v/t51.2885-15/e35/104418570_713138709525676_2431057879476108410_n.jpg?_nc_ht=scontent-gmp1-1.cdninstagram.com&_nc_cat=104&_nc_ohc=YI7DZfikd18AX8Lf6mh&oh=3c02c1a82078b7b6ffd33608a6b8b376&oe=5F232C00"
/>
</div>
<div className="feedLogo">
<div className="feedLogoLeft">
<img
alt="하트"
src="https://s3.ap-northeast-2.amazonaws.com/cdn.wecode.co.kr/bearu/heart.png"
/>
<img
alt="말풍선"
src="https://s3.ap-northeast-2.amazonaws.com/cdn.wecode.co.kr/bearu/comment.png"
/>
<img
alt="공유"
src="https://s3.ap-northeast-2.amazonaws.com/cdn.wecode.co.kr/bearu/share.png"
/>
</div>
<img
alt="북마크"
src="https://s3.ap-northeast-2.amazonaws.com/cdn.wecode.co.kr/bearu/bookmark.png"
/>
</div>
<div className="feedReply">
<div className="replyLikeTotal">
<img
alt="토트넘 프로필"
src="https://scontent-gmp1-1.cdninstagram.com/v/t51.2885-19/s320x320/91813079_951055115342792_3781464304625123328_n.jpg?_nc_ht=scontent-gmp1-1.cdninstagram.com&_nc_ohc=ctRc2X7wrHYAX9MMcfT&oh=84bfa84d58a12c228a70cada7426ba18&oe=5F24D9AF"
/>
<p>tottenham_official님 외 7천명이 좋아합니다</p>
</div>
<div className="replyContent">
<ul>{commentList}</ul>
</div>
<div className="replyTime">
<p>42분 전</p>
</div>
</div>
<div className="feedComment">
<input
type="text"
value={this.state.typeComment}
onChange={this.textChange}
onKeyUp={this.handleKeyPress}
className="commentBox"
placeholder="댓글 달기..."
/>
<button onClick={this.add} className="commentBtn">
게시
</button>
</div>
</div>
</div>
);
}
}
export default Feed;
**import 순서는 보통 패키지 > 컴포너트 > 이미지 파일 > .scss 순이 좋다
** 최상단의 감싸주기 위한 div는 React Fragment 를 사용하는 것이 좋다!
<div> // <>
<div>
<Nav />
</div>
<div className ="mainContainer">
<Feed />
<MainRight />
</div>
</div> //<>
변수명은 그것 자체만으로 어떤 의미인지 직관적으로 파악이 되어야 한다.
<<myCode
this.state = {
backgroundColor : "",
id : "",
password : "",
ready : false,
myId : "djaxornwkd12@gmail.com",
myPassword :"qudtn12",
passwordError : false
}
여기서 state 값으로 ready를 줬지만 그 자체로 어떤 준비? 인지 알기 힘들다
inputPasswordValue = (e) => {
this.setState({
password : e.target.value,
ready : e.target.value.length>5&&this.state.id.includes('@') ? true : false
})
}
<button className={this.state.ready ? "login ready" : "login btn"}
onClick={this.goToMainPage}>로그인</button>
결국 ready는 btn의 색깔을 바꾸기 위한 조건이므로
isBtnValid
등의 변수명이 적절하다