생활코딩 React강의
개요
Component 작성으로 얻는 것
- 가독성
- 재사용성
- 유지보수
개발환경
-
nodejs 설치
- cmd에서 npm -v 를 입력하여 설치확인
-
create-react-app 설치
- cmd 상에서 (실습용)
npm install -g create-react-app@2.1.8
(실제 사용시 최신버전을 쓸때 npm대신 npx사용)
-
세팅
- 폴더 생성
- cmd에서 폴더로 이동후
create-react-app .
- 웹앱 실행
npm run start
-
배포
- 브라우저 reload에 우클릭해서 ‘Empty Cache and Hard Reload’해서 보면 1.7M를 다운로드한다.
- 개발모드에서는
npm run start
- 빌드할때는
npm run build
이렇게 하면 build 폴더가 생기고 살펴보면 공백이 없고 폴더내 html 파일 용량이 줄어든다.
- 실제 서비스 할때는 buil 폴더 안의 파일을 사용한다.
- serve 한번만 실행시킬 웹서버 실행
npx serve -s build
-
Component 생성
class Subject extends Component {
render(){
return(
<header>
<h1>WEB</h1>
world wide web!
</header>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Subject></Subject>
</div>
);
}
}
- Subject라는 Class를 만든다.
- Class 안에서 function 단어 생략
- JS 문법과 다른 JXS
- Component는 정리정돈의 개념으로 복잡도를 낮춤
class Subject extends Component {
render(){
return(
<header>
<h1>{this.props.title}</h1>
{this.props.sub}
</header>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Subject title='WEB' sub="world wide web!"></Subject>
<TOC></TOC>
<Content></Content>
</div>
);
}
}
- props 이용하여 사용자 정의 태그
-
크롬 확장 프로그램
- React Developer Tools을 이용하여 브라우저에서 리액트로 상태 확인 가능
-
Component 파일로 분리하기
import React, { Component } from 'react';
class TOC extends Component {
render(){
return (
<nav>
<ul>
<li><a href="1.html">HTML</a></li>
<li><a href="2.html">CSS</a></li>
<li><a href="3.html">HTML</a></li>
</ul>
</nav>
);
}
}
export default TOC;
- 새 파일에 Component를 복사하고 Import하고 다른 파일에서 사용할 수 있게 export 구문을 작성한다.
import TOC from "./components/TOC";
- 분리된 Component를 사용할 파일에서 import한다.
- state
- React에서 Component를 외부에서 조작할 떄는 props를, 내부적으로 상태를 관리할 때는 state를 사용한다.
- props are read-only, state can be modified
constructor(props){
super(props);
}
- Component를 실행할 때 Props를 초기화 시켜주는 코드
this.state = {
subject:{title:'WEB', sub:'World Wide Web!'}
}
- state에 초기값 지정
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
</Subject>
- title과 sub를 state에서 가져온다.
- 내부적으로 사용하고 외부에 노출하지 않으므로 사용성을 높인다.
- 반복문일때 key 값을 지정해주지 않으면 에러 발생
- event
- code에 debugger를 넣으면 브라우저에서 그부분에서 실행이 멈춘다.
function(e){
e.preventDefault();
}
- event들의 기본적인 동작 방법을 못하게 할때는 preventDefault()를 사용한다.
<h1><a href="/" onClick={function(e){
console.log(e);
e.preventDefault();
//this.state.mode = 'welcome';
this.setState({
mode:'welcome'
});
}.bind(this)}>{this.state.subject.title}</a></h1>
- 함수안에서 this를 사용하면 에러가 뜨므로 .bind(this)를 넣어준다.
functionA.bind(B)
- bind는 어떤 함수(functionA)내에서 this의 값(B)을 지정해준다.
- state 변경은 this.setState로 한다.
- component에서 state가 정해져 있으므로 함수의 형태로 바꿔줘야한다.
- Create
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
}.bind(this)}
>
- form tag에 onSubmit을 이용
//this.state.contents.push(
// {id:this.max_content_id, title:_title, desc:_desc});
var _contents = this.state.contents.concat(
{id:this.max_content_id, title:_title, desc:_desc}
)
this.setState({
contents:_contents
- push는 원본 배열을 변경하는것이고 concat은 다른 변수에 원본에 추가한 배열로 설정하므로 원본은 변하지 않는다.
shouldComponentUpdate(newProps, newState){
console.log('==>TOC render shouldComponentUpdate'
,newProps.data
,this.props.data
);
if(this.props.data === newProps.data){
return false;
}
return true;
}
- render함수 이전에 shouldComponentUpdate가 실행된다.
- return값이 True면 render함수가 실행되고, False면 render가 실행되지 않는다.
- concat을 쓰지 않고 push를 사용했다면 원본값이 바뀌어서 성능을 향상하기 어렵다.
var a = [1,2];
var b = Array.from(a);
b.push(3);
- array에서 Array.from을 쓰면 복제가 된다.
var a = {name:'egoing'};
var b = Object.assign({},a);
- 객체에서는 Object.assign을 사용하면 복제가 된다.
- immutable
- Update
constructor(props){
super(props);
this.state = {
title:this.props.data.title
}
}
- 함수내에서 props를 불러오면 readonly롤 수정이 안된다. 이를 리액트에서 변수에 props를 지정하면 경고가 뜨게 해놓았다.
- 그러므로 state화 함.
type="text"
name="title"
placeholder='title'
value={this.state.title}
onChange={function(e){
this.setState({title:e.target.value});
}.bind(this)}
- onChange를 사용하여 readonly를 해제한다.
- 해당값은 value로 지정한다.
inputFOrmHandler(e){
this.setState({[e.target.name]:e.target.value});
}
onChange={this.inputFormHandler.bind(this)}
- inputFormHandler 함수로 반복되는 부분 제거
- e.target.name을 써서 title과 desc를 대응하도록 한다.
this.inputFormHandler = this.inputFormHandler.bind(this);
- constructor안에 상기문을 입력하면 bind(this)를 매번 입력하지 않아도 된다.
- Delete
if(_mode === 'delete'){
if(window.confirm('really?')){
var _contents = Array.from(this.state.contents);
var i = 0;
while(i < this.state.contents.length){
if(_contents[i].id === this.state.selected_content_id){
_contents.splice(i,1);
break;
}
i = i +1;
}
this.setState({
mode:'welcome',
contents:_contents
})
}
}
- confirm창은 window.confirm사용
- delete는 splice(시작, 갯수)지정으로 삭제한다.
- ps
- immutable.js
- react router : react는 하나의 url로 모든 페이지를 만듦. url에따라서 적당한 component가 실행되게 만든다.
- npm run eject : create-react-app의 여러 설정을 수정 가능
- redux : 중앙에 저장소가 있고 component가 연결된다.
- react native : react와 같은 방법으로 native 앱을 만들수 있다.
- …this.state
- 앞의 내용을 그대로 유지한다는 의미
- {this.state.movies ? this._renderMovies() : ‘Loading’}
- this.state.movies가 참이면 this._renderMovies()가 실행되고, 거짓이면 ‘Loading’이 출력된다.
- component 중에 state 및 생애주기함수가 필요없는 것은 function으로 간단하게 표현한다.
- class에서는 props에 this가 필요하지만 function에는 this가 필요없다. 이미 props를 쓰니까
- fetch(‘주소’)를 이용해서 불러올수 있다.
- 새로고침 없이 작업이 가능하고, 리액트와 작업이 간편하기 떄문에 AJAX 추천
fetch('https://yts.mx/api/v2/list_movies.json?sort_by=rating')
.then(potato => potato.json())
.then(jason => console.log(jason))
.catch(err => console.log(err))
-
fetch로 url을 불러오고 성공적으로 수행했을때 .then으로 받고 실패 했을때 catch로 받을 수 있다.
-
fetch가 좋은 이유는 url을 AJAX로 심플하게 불러올수 있어서 좋다.
-
.then이 많아지면 callback hell에 빠질 수 있다. 이때 사용하는 것이 sync, await
- async는 비동기로 이전작업이 끝나지 않아도 다음 작업이 시작하는 형태
componentDidMount(){
this._getMovies();
}
_getMovies = async () => {
const movies = await this._callApi()
}
_callApi = () => {
fetch('https://yts.mx/api/v2/list_movies.json?sort_by=rating')
.then(potato => potato.json())
.then(jason => console.log(jason))
.catch(err => console.log(err))
}
- did mount하고 나면, get movies를 한다. 이건 asynchronous function인데 movies라는 variable을 갖고 있다. 그리고 이건 value를 갖고 있는데 call api라는 function을 await 모드에서
- await으로 하는것은 call api 기능이 끝나는 것(성공적으로 수행이 아니라)을 기다리고 있는것이다.
- _callApi()의 return value를 movies에 set
- => arrow function은 return이 필요없다.
- className은 css에서 class를 의미
- 배포
- npm run build
- gh-pages 깃허브 페이지에 배포시 설치
- npm install –save gh-pages
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
}
"homepage": "https://username.github.io/movie_app"
- package.json 에 상기 내용 추가
- npm install react-router-dom 라우터 설치
import { BrowserRouter, Route} from "react-router-dom";
import Home from "./routes/Home";
import About from "./routes/About";
function App() {
return(
<BrowserRouter>
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
</BrowserRouter>
);
}
export default App;
- react route는 주소 경로에 맞는 것을 모두 보여준다.
- 그 경로에 딱 맞는 것만 출력하려면 exact={true} 삽입
import React from "react";
import { Link } from "react-router-dom";
function Navigation(){
return(
<div>
<Link to="/" >Home</Link>
<Link to="/about" >About</Link>
</div>
);
}
export default Navigation;
- Navigation 작성시 Router는 href가 아닌 Link to를 사용한다.
React class vs function style
- 최신 react에 hook이 지원하면서 function에 state와 life cycle function을 사용할수 있게 되었다.
- 내장 hook은 보통 use라고 적혀있다.
- useState는 배열로 첫번째 값은 상태값, 두번째 값은 상태를 바꿀 수 있는 함수
- useEffect = componentDIdMount & componentDidUpdated
- useEffect의 return은 다시 시작될때 clean up 한다.
- useEffect의 두번째 인자를 [xxx]로 넣으면 [xxx]안의 인자가 바뀌었을때만 실행된다.
- 두번째 인자를 빈 배열[]로 넣으면 componentDidMount만 실행