React 기능 정리 및 React로 다시 구현한 인스타그램 코드 리뷰🤹🏼♀️
기존에 TIL을 통해 사용한 코드에 대해서는 정리했지만 조금 더 자세하게 flow에 맞추어서 설명과 함께 정리하면서 한 주 간 배운 리액트에 대해 정리하려 한다.
Login/Main Component
는 주석처리 해서 localhost:3000
에서 띄워놓고 코드를 입력했다. import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Login from './pages/Login/login';
import Main from './pages/Main/main';
ReactDOM.render(
<Login />,
// <Main />,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
index.css
파일에 저장하고 그걸 import해왔다는 뜻인데 경로롤 보자면 index.html와 index.css 는 같은 src 파일 안에 위치함으로 현재 파일위치를 나타내는 ./
이후파일이름을 입력함으로서 경로로 이동하도록 한다. path intelligence extension
을 입력하면 좀 더 간편히 경로를 찾을 수 있다.import Login from './pages/Login/login';
import Main from './pages/Main/main';
.
..
사용을 통해 원하는 파일 위치를 입력하면 된다.ReactDOM.render(
<Login />,
// <Main />,
document.getElementById('root')
);
ReactDOM.render(a,b)
즉 a를 b에 보여줘 라는 내용인데, a 는 JSX
형태로 입력해야하며 보통 들어갈 내용을 Component로 나누어관리해 각 Component안에 입력해준다. 먼저 react를 사용할 index.html
에 <body><div Id="root></div></body>
를 입력해 주었기 때문에 우리는 화면에 구현할 내용을 document.getElementById('root')
에 보여줘 라고 나타내고 있는 것이다. import React, { Component } from "react";
import './login.css';
import logo from '../../images/login/logo_text.png';
class Login extends Component {
constructor() {
super();
this.state = {
IDInput: "",
passwordInput: "",
ready: false
}
}
idChangeHandler = e => {
this.setState({
IDInput: e.target.value
})
}
passwordChangeHandler = e => {
this.setState({
passwordInput: e.target.value,
ready: e.target.value.length > 5 && this.state.IDInput.includes("@") ? true : false
})
}
clickHandler = e => {
e.preventDefault();
console.log("ID", this.state.IDInput)
console.log("Password", this.state.passwordInput)
// console.log(this.state.passwordInput.length&&this.state.IDInput.includes("@"))
}
render() {
return (
<div>
<div class="whole-box">
<div className="container">
<div id="logo-holder">
<img src={logo} alt="instgram logo" />
</div>
<form id="login-form">
<div className="formcontainer">
<input onChange={this.idChangeHandler} type="text" id="username-field" className="login-form-field" placeholder="전화번호, 사용자 이름 또는 이메일" />
<input onChange={this.passwordChangeHandler} type="password" id="passwsord-field" className="login-form-field" placeholder="비밀번호" />
<input className={this.state.ready ? "ready-to-submit" : "not-ready-to-submit"} onClick={this.clickHandler} type="submit" value="로그인" />
</div>
</form>
<div className="linkContainer">
<a className="forgotPW" href="#">비밀번호를 잊으셨나요?</a>
</div>
</div>
</div>
</div>
);
}
}
export default Login;
import React, { Component } from "react";
class Login extends React.Component
import './login.css';
./login.css
로 작성이 가능하다.
import logo from '../../images/login/logo_text.png';
페이지에 url이 아닌 저장된 이미지를 사용한 부분은 logo 를 import 해주고 logo가 들어가야 하는 위치에 {logo}
로 표현해준다.
JSX에 자바스크립트 코드로 들어가야할 내용은 항상 중괄호 안에 위치하게 한다 { }
사용할 이미지 파일은 images
폴더를 만들어서 별도로 관리해주었다. (사실 폴더를 만들만큼 사진이 많지는 않지만, 나중에 프로젝트 할땐 많을 거니깐 먼저 file 전체의 architecture를 잘짜는 연습이라고 생각
하면 될 것같다!)
class Login extends Component {
constructor() {
super();
this.state = {
IDInput: "",
passwordInput: "",
ready: false
}
}
Component는 function Component
와 class Component
형태가 있는데, hook을 사용하는 더 편리한 function Component
는 다음 프로젝트부터 적용해보도록 하고 금번 인스타그램 기능은 기본에 충실한 class Component
로 구현해 보도록 한다.
Class component는 실행하자마자 constructor 함수
가 실행되고 constructor 함수는 super()
와 꼭 함께 사용해야 한다. (
공식 문서 설명 첨부
In JavaScript classes, you need to always call super
when defining the constructor of a subclass.
All React component classes that have a constructor
should start with a super(props) call.
Component는 constructor
내부에 this.state
를 설정해서 Component의 상태를 정할 수 있다.
먼저 로그인 시 사용자가 input 값을넣을 아이디 값, 비밀번호 값, 버튼 활성화 상태가 필요하므로 첫 state에 위와 같이 빈 string
과 false
로 설정해준다
idChangeHandler = e => {
this.setState({
IDInput: e.target.value
})
}
구현하고자 하는 기능은 사용자가 ID값을 넣었을때 그 값을 현재 상태로 지속적으로 업데이트를 해야 한다. ID/Password validation 확인 할때 그 저장된 값을 기준으로 확인이 가능하기 때문이다.
아래 아이디가 들어가야 할 Input 태그 자리에 onchange
함수를 설정해주고, 값이 입력될때 설정을 해야 하므로 해당 함수는 event 값을 parameter로 받는 형태
의 함수 구조를 만들어준다 idChangeHandler = e => {}
사용자가 input 에 입력하는 value를 이전에 정의한 this.state.IDInput
으로 업데이트 되게 하기 위해서는 this.setState
를 사용한다.
this.setState({IDInput = e.target.value})
를 사용하면, 우리는 React에게 해당 component를 re-render 해줘
라고 말하는것이고 re-render 하면서 state값을 setState값으로 업데이트 하는 것이다.
함수가 실행되면 아래 render() 이후의 this.state.IDInput
이 업데이트 되는 것이므로 constructor() 와 render() 사이에 위치하게 한다.
'setState`는 비동기 함수이다. 순서대로 실행 되지 않고 특정 이벤트가 실행 될때 실행된다고 보면 된다.
passwordChangeHandler = e => {
this.setState({
passwordInput: e.target.value,
ready: e.target.value.length > 5 && this.state.IDInput.includes("@") ? true : false
})
}
e.target.value
로 setState
를 저장해준다ready : false
를 접근해 봅니다.(이름은 직관적으로 지어야 한다고해서 로그인 준비가 되었냐 말았냐의 ready를 썼는데.. 다른사람들 눈에도 그렇게 보일지는 모르겠다..):
이후에 삼항연산자를 쓴 구조이다. (사실 처음에 이구조를 짰을때, 삼항 연산자에도 :
가 들어가서 이게 되나? 했는데 코드가 되길래 아하? 하면서 사용하게 되었다. 코드는 치면서 터득하는중.. 되는지 안되는지는 그냥 쳐보자 그럼 알수있다 !! )ready: e.target.value.length > 5 && this.state.IDInput.includes("@") ? true : false
&&
true
가 되고 아니면 false
가 된다. clickHandler = e => {
e.preventDefault();
console.log("ID", this.state.IDInput)
console.log("Password", this.state.passwordInput)
}
render() {
return (
<div>
<div class="whole-box">
<div className="container">
<div id="logo-holder">
<img src={logo} alt="instgram logo" />
</div>
<form id="login-form">
<div className="formcontainer">
<input onChange={this.idChangeHandler} type="text" id="username-field" className="login-form-field" placeholder="전화번호, 사용자 이름 또는 이메일" />
<input onChange={this.passwordChangeHandler} type="password" id="passwsord-field" className="login-form-field" placeholder="비밀번호" />
<input className={this.state.ready ? "ready-to-submit" : "not-ready-to-submit"} onClick={this.clickHandler} type="submit" value="로그인" />
</div>
</form>
render()
안의 내용은 화면에 보여질 내용을 보여준다. 먼저 처음에 render()가 실행되고 this.함수명
이 실행되면 re-render 되면서 변경된 setState값을 적용하는 순서라고 보면 된다. render() { return()}
형태로 되어있고 return()
안에는 최상위 요소로 감싸야 한다. 보통은 <div></div> 혹은 <> </>
react fragment형태로 작성한다.onChange
와onClick
함수는 ={}
형태로 중괄호 안에 표현해주며, 예를들어 안에 삼항연산자가 들어간 submit button
의 경우 아래와 같이 표현한다. <input className={this.state.ready ? "ready-to-submit" : "not-ready-to-submit"} -css 코드에
ready-to-submit과
not-ready-to-submit`을 만들어 두고 각각 준비가 안됬으면 연한 파랑 컬러, 준비가 되었으면 진한 파랑컬러로 설정 해두고, true와 false 상태에 따라 변경되도록 한다.
<div className="linkContainer">
<a className="forgotPW" href="#">비밀번호를 잊으셨나요?</a>
</div>
</div>
</div>
</div>
);
}
}
export default Login;
export
해서 부모component에서 사용,인용 될수 있도록 입력한다.
조건 : 댓글 적고 게시 버튼을 누르거나, 'Enter'키를 입력 하였을 때 댓글이 입력 되도록 할 것
이전에 기본적인 import 문법은 정리하지 않고 새로 생성된 부분만 정리 할것
전체코드를 component화 하여 나누었고, feed 부분에만 react를
import React, { Component } from "react";
import './main.css';
import Header from "../.././components/Header.js";
import Feed from "../.././components/Feed.js";
import Rightfeed from "../.././components/Rightfeed.js";
class Main extends Component {
render() {
return (
<>
<Header />
<main>
<Feed />
<Rightfeed />
</main>
</>
);
}
}
export default Main;
header, feed, rightFeed
세 부분으로 나누었고, feed와 rightfeed는 결국 main
을 부모 요소로 두기 때문에 <main></main>
안에 순서대로 입력해주었다.Login 페이지 처럼 전체 코드넣고 부분 코드 넣는 식으로 하려 했지만 feed 페이지 꾸미는데 있는 JSX 코드가 많아서 실제로 기능구현에 사용된 JSX와 function 담긴 부분만 설명해보려고 한다.
처음 코드를 만들었을때 comment : ""
만 this.state
에 추가했고, map
함수는 쓰지 않고 댓글이 들어가야 할 자리에 {this.state.comment}
를 넣었다. changeHandler
로 setState를 입력한 값으로 바꿨으니깐 하고 넘어갔는데, 실상은 그게 아니었다.
댓글을 달면 계속 추가되어야 하는데. {this.state.comment}
로 끝내버렸으니, 당연히 댓글은 한개밖에 작성할 수 없다.
그렇다면 this.state.comment
해서 작성한댓글을 놔두고 새로 작성한 아이들이 순서대로 차곡차곡 보여주는 형식으로 해야하는데 어떻게 구현해야할까?
작성하고 게시가 되면 그 게시된 글을 차곡차곡 빈 array에 넣어놓고 새로 추가하는 것들은 순서대로 출력 되도록 해야한다.
이 기능을 구현하려면 . 그렇게 했을땐 댓글 한 개 추가는 가능했지만 그 이상을 넣어야 함으로 구글링 하다 해당 영상을 발견하고 코드에 많은 도움을 받았다.(https://www.youtube.com/watch?v=A2PKZlzbOtI&list=WL&index=2&t=0s)
즉 comments
라는 빈 array
(입력하는 값이 순서대로 담길 빈배열) 와 map 함수 : 배열하나하나를 돌면서 입력해준 조건이 적용된 배열을 출력하는 함수
로 해결할 수 있었다.
this.state = {
comments : [],
comment : ""
}
}
changeHandler = (e) =>{
this.setState ({comment : e.target.value})
}
handleKeyPress = (e) => {
e.keyCode === 13 && this.clickHandler()
}
OnKeyUp={this.handleKeyPress}
이벤트를 주고 &&
으로 항상 true만있는조건을 표현해 주었다. 예를들어 위의 코드를 삼항 연산자로 바꾸면e.keyCode===13? this.clickHandler() : null
로 나타낼 수 있는데 null은 렌더링 하면 아무것도 보여주지 말라는 뜻이다. null 값처럼 false에아무것도 일어나지 않는다면 &&
을 통해 조건부 렌더링이 가능하다. clickHandler = () => {
let comments = this.state.comments
let comment = this.state.comment
comments.push(comment)
this.setState({comments : comments})
}
comment
들을 comments array
에 넣어주게 되는데, 게시 버튼을 클릭함과 동시에 빈 배열인 comments에 push 함수를 통해서 추가하고 setState를 통해 배열을 새로운 comments 로 업데이트 한다. react dev tool
을 켜서 실시간으로 state에 들어가는 comment array를 확인하고 나니 이해가 잘 되었다. <section className="new-comment">
{this.state.comments.map ((comment) => { return (
<span><strong>joanne_jhk</strong> {comment} </span>)})}</section>
map함수
가 나오는데 입력한 comments 가 있는 배열
에서 setState에 업데이트 된 comment를 parameter로 받아
입력한 comment
를 하나씩 화면에 하나씩 보여주게 한다. 간단한 이 맥락을 이해하는데 꽤 오랜시간이 걸렸ㄷ...ㅠㅠ 익숙해 지겠지?https://github.com/junghyunhao/InstagramCloneinReact