(1~4번 영상)
리액트 소개 및 특징
(5번 영상)
-
코드들을 의존하는 순서대로 하나 또는 여러개의 파일로 만들어줌
-
gulp 와 비슷. 더 좋다
- 여러개의 자바스크립트 파일을 하나도 만들어 주거나 규칙에 따라 분리할 수도 있다.
- ES6 - 모던 자바스크립트 사용할 때 구형브라우저에서 지원이 안되서 바벨을 이용해 변환하여 여러종류의 브라우저에서 실행 하능
- 프로젝트를 만들 때 전체적으로 파일들을 관리해 주는 도구
- 자바스크립트 변환 도구
- 노드나 자브스크립트 엔진에서 모든 문법을 지원해 주지는 않음
- 리액트는 JSX 문법을 사용해 컴포넌트를 작성하는데 이때 바벨을 사용함
[문법]
import : 모듈을 사용함
class : Component 를 만듬 (다른 방법 - 함수를 통해서 만들 수 잇음)
render : 반드시 JSX 형태의 코드를 return 해줘야 함
(6번 영상)
- JSX : HTML 처럼 생긴 문법이 자바스크립트 코드로 변환됨
- 태그는 반드시 받혀야 한다
최상위 element는 꼭 하나여야 한다. (태그가 2개 이상일 경우 최상위에 하나의 태그로 감싸줘야함)
이 경우 불필요한 최상위 element가 하나 생기게 되는데 React 16.2 이상에서 fragment 기능으로 방지할 수있다.
- JSX 안에서 자바스크립트 값을 사용할 때는 {변수명} 으로 사용한다
- var 변수는 scope 가 함수 단위이다.
function foo(){ scope 단위 ┐
var a = 'hello' │
if(true) { │
var a = 'bye' │
console.log(a) // bye │
} │
console.log(a) // bye ┘
- const, let 변수는 scope 가 블록 단위이다.
function foo(){ scope 단위 ┐
let a = 'hello' ┘
if(true) { ┐
let a = 'bye' │
console.log(a) // bye ┘
} ┐
console.log(a) // bye ┘
ES6 에서 var 은 더이상 쓰지 않음
고정 상수는 const, 일반 변수는 let 사용
JSX 내부에서 조건식 사용하기
1)
삼항 연산자 사용 ( 조건 ? true : false )
2)
&& 연산자 사용
3)
function 함수 작성 ( => 화살표 함수로도 사용 가능. 화살표 함수는 this, argument super 가 없는 함수임)
+ self closing tag : <input />
(7번 영상)
@ JSX 에서 css 스타일과 class 사용방법
React 사용방법은 기존 css 사용법과 조금 다르다
- Style 을 객체 형태로 넣어줌
- 속성은 기존 단어가 아닌 특수문자를 제외하고 camel case 로 적는다.
- class 는 className 으로 입력해야 한다.
const style = {
backgroudColor : 'red', // 기존 : backgroud-color
color : 'white',
fontSize : '36px' // 기존 : font-size
}
// 적용방법
<div style={style} className="app">
</div>
JSX 내부에서 주석은 그냥 출력되어 버린다.
일반 주석 및 멀티라인 주석 모두 출력됨.
일반적으로 주석은 멀티라인으로 작성하고 {} 로 감싸준다
// 주석
/*
주석
*/
위 두 주석 모두 오류
일반적으로 주석은 멀티라인
{/* 주석 사용 */}
태그 사이에는 그냥 주석 사요 가능
<h1
// 주석 가능
>
</h1>
(8번 영상)
주제 : Props
- Props : 부모에서 자식으로 일방적으로 전달. 자식에서 값을 변경할 수 없다.(읽기 전용)
- <Child value = "value"> : value 가 props 이다
default props 값을 class 내부에 static 으로 지정해 놓을 수 있다
class 외부에 설정할 수 있지만 static 으로 사용하는게 최신 자바스크립트 문법에 더 알맞다.
- 기본 static 사용법 (최신 사용법)
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
static defaultProps = {
name : 'basic'
}
render() {
return (
<div className="App">
props test : {this.props.name}
</div>
);
}
}
export default App;
- 외부 설정
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
props test : {this.props.name}
</div>
);
}
}
App.defaultProps = {
name : 'basic'
}
export default App;
- 단순히 불러오기만 할 class 일 경우 함수형 component 로 만든다
- SampleFunctionalCoimponent.js
import React from 'react'
const SampleFunctionalComponent = ({ test }) => {
return (
<div>hi this is sample functional component : {test}</div>
);
};
SampleFunctionalComponent.defaultProps = {
test : 'test hi'
}
export default SampleFunctionalComponent;
- App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import SampleFunctionalComponent from './SampleFunctionalComponent'
class App extends Component {
static defaultProps = {
name : 'basic'
}
render() {
return (
<SampleFunctionalComponent />
);
}
}
export default App;
1) import 에 Componenet 선언이 필요없다
2) class 선언이 아니고 하나의 변수로 만든다
3) 함수형 컴포넌트의 파라미터 (=test) 는 비구조화 할당 문법이 사용됨.
4)
* 비구조화 할당 문법
: 여러 변수 또는 파라미터를 각각의 값에 맞게 할당할 때 하나씩 지정해 주지 않고 객체로 한번에 지정해 주는 방식
- 함수형 컴포넌트와 클래스형 컴포넌트의 차이점 (함수형 컴포넌트 기준)
- state 기능이 없음
- life cycle 없음
> 장점
- 초기 마운트 속도가 미세하게 빠르다
- 불필요한 기능이 없어서 메모리 자원을 덜 사용한다
- 어떤값을 가져와서 단순히 보여주기만 한다면 함수형 컴포넌트가 약간 더 효율적이다
- 컴포넌트가 매우매우 많다면 조금 더 효율적이겠지만 크게 차이나지는 않을 것이다.
-
Class Field 문법 : https://tc39.github.io/proposal-class-fields/
(9번 영상)
주제 : state
* state : 컴포넌트 스스로가 가지고 있는 객체. 따라서 컴포넌트 스스로가 값을 변경 할 수 있다. (setState 사용)
- 카운터 하는 소스 작성... ( 카운터에 나오는 숫자는 유동적. 숫자가 바뀔때 마다 rerender 해줘야 한다. )
* 아래는 전부 class 안에 정의한다.
1) state 정의 : 객체여야 한다. 문자열, 숫자 안됨.
2) 객체 안에 요소를 정의 한다.
3) 카운터 값을 변경하기 위해 custom method 를 만든다.
4) 카운터 기능을 위해 증가 감소 함수를 만드는데, 함수 안에서 state 값을 직접 조절하면 안된다.
컴포넌트에서 state 값이 update 된지 모른다.
5) state 값이 변경되는걸 component 가 알기 위해서는 항상 setState 함수를 통해 변경해줘야 한다.
- 잘못된 state 사용방법
handleIncrease = () => {
this.state.counter = this.state.counter + 1;
}
- 올바른 사용방법
import React, { Component } from 'react';
class Counters extends Component {
state = {
counter : 0
}
handleIncrease = () => {
this.setState({
counter : this.state.counter + 1
})
}
handleDecrease = () => {
this.setState({
counter : this.state.counter - 1
})
}
render(){
return(
<div>
<h1>counter</h1>
<div>value : {this.state.counter}</div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counters;
* render 함수는 그냥 함수로 작성했는데 increase, decrease 함수는 왜 화살표 함수( => )로 작성했을까?
: 증감 함수를 화살표가 아닌 기본 함수로 작성하게 되면 함수 안에서 this 가 어느것을 가리키는지 모르게 된다.
: 해당 문제를 해결해주기 위해서는 constructor 를 이용해야 한다.
1) counter component 가 생성될 때 항상 constructor 가 제일 먼저 실행되고,
2) constructor 에서는 상속받은 Component 의 기본 생성함수를 먼저 호출해주도록 한다. ( super 사용 )
3) 그 다음 counter component 에서 사용되는 increase, decrease 함수의 this 가 constructor 의 this 라는걸 명시해 준다. ( binding 해줌 )
- 예시
import React, { Component } from 'react';
class Counters extends Component {
state = {
counter : 0
}
constructor(props){
super(props);
this.handleIncrease = this.handleIncrease.bind(this);
this.handleDecrease = this.handleDecrease.bind(this);
}
handleIncrease() {
this.setState({
counter : this.state.counter + 1
})
}
handleDecrease = () => {
this.setState({
counter : this.state.counter - 1
})
}
render(){
return(
<div>
<h1>counter</h1>
<div>value : {this.state.counter}</div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counters;
* props 는 부모자 자식에게 넘겨주는 변경 불가능한 값
* state 는 자기 자신이 가지고 있는 변경 가능한 값
lifecycle api : https://react-anyone.vlpt.us/05.html
(10번 영상)
주제 : life cycle api
* life cycle api 사용 시기
1) component 가 브라우저에 나타날 때
2) component 가 브라우저에서 업데이트 될 때
3) component 가 브라우저에서 사라질 때
* 종류 (매우 많다)
1. Mount - Component 가 브러우저에 나타남
1) constructor : Component 가 만들어질 때 가장 먼저 실행되는 함수
2) getDerivedStateFromProps : props 로 받은 값을 그대로 state 에 동기화 시키고 싶을 때 사용 (mount, update 두 부분에서 사용)
3) render : DOM, 태그 등등 정의
* 이후 브라우저에 표시되고 난 다음
4) componentDidMount : 외부 라이브러리, 차트 라이브러리 등등 사용할 때, ajax, api 요청을 할 때 이곳에서 실행
뷰가 다 그려지고 스크롤을 이동, 이벤트 listening
2. Update - Component 에서 props, state 값이 변경됨
1) getDerivedStateFromProps : props 로 받은 값을 그대로 state 에 동기화 시키고 싶을 때 사용 (mount, update 두 부분에서 사용)
2) shouldComponentUpdate : (중요) component 가 update 되는 성능을 최적화 시킬 때 사용
- 부모 component 가 rerender 되면 자동적으로 자식 component 도 rerender 된다. 하지만 불필요할 때가 있다.
- react 는 virtual DOM 을 사용하지만 기본적으로는 rerender가 발생하면 기본 DOM 과 virtual DOM 둘 다 다시 그린 후 변경점을 비교하게 된다
- 이 기능을 사용하게 되면 virtual DOM 에 그리는 것조차 막아서 뷰의 변경을 방지 할 수 있다. (성능 최적화 관점)
- 해당 함수는 true, false 값을 반환하며, true 는 render 실행, false 는 실행 안함
* render 가 실행되고 브라우저에 반영되기 바로 직전
3) getSnapshotBeforeUpdate : render 되고 브라우저에 표시되기 전에 이 함수에서 특정 로직을 수행한다.
- 스크롤 위치, DOM 크기 가져오기 등등
* 위 작업들을 모두 마치고 component 가 모두 update 되고난 후
4) componentDidUpdate : state 가 변경되었을 때 이전 상태와 현재 상태를 비교해서 특정 작업을 해야할 때
3. Unmount - Component 가 브러우저에서 사라짐
1) componentWillUnmount : 마운트 때 listen 시킨 이벤트들을 해제할 때 사용됨
lifecycle api : https://react-anyone.vlpt.us/05.html
(11번 영상)
주제 : life cycle api
* 코드 샘플
1. constructor
- 컴포넌트가 제일 먼저 만들어질 때 호출됨.
- super 사용 용도 : 상속받은 Component 의 원래 가지고 있던 생성자를 먼저 호출해 주고 작업을 하도록 하기 위함
class App extends Component {
constructor(props){
super(props);
console.log('constructor')
}
........
}
2. componentWillMount
- 사라짐
3. componentDidMount
class App extends Component {
constructor(props){
super(props);
console.log('constructor')
}
componentDidMount(){
console.log('componentDidMount')
}
.................
}
* 특정 DOM 에 어떤 작업을 하고 싶을 때 ref 사용. ( 태그에 아이디를 붙이는 것과 비슷함. ref 로 직접 가져올 수 있다. )
class App extends Component {
constructor(props){
super(props);
console.log('constructor')
}
componentDidMount(){
console.log('componentDidMount')
console.log(this.myDiv.getBoundingClientRect())
}
render() {
return (
<div ref={ref => this.myDiv = ref}>
hi
</div>
);
}
}
4. componentWillReceiveProps
- 16.3 부터 사라짐
5. getDerivedStateFromProps
- 16.3 부터 사용 가능
- setstate 사용 불가.
- 변경 할 state 값을 바로 return 해주면 setState 사용하지 않고도 state 에 값이 적용된다.
- state 와 props 값의 동기화
[StateComponent.js]
import React, { Component } from 'react';
class StateComponent extends Component {
state = {
value : 0
}
static getDerivedStateFromProps(nextProps, prevState){
if(prevState.value != nextProps.value){
return {
value : nextProps.value
}
}
return null;
}
render(){
return(
<div>
<p>props : {this.props.value}</p>
<p>value : {this.state.value}</p>
</div>
);
}
}
export default StateComponent;
[App.js]
import React, { Component } from 'react';
import StateComponent from './StateComponent'
class App extends Component {
state = {
count : 1
}
constructor(props){
super(props);
console.log('constructor')
}
componentDidMount(){
console.log('componentDidMount')
// console.log(this.myDiv.getBoundingClientRect())
}
handleClick = () => {
this.setState({
count : this.state.count + 1
})
}
render() {
return (
<div>
<h1>hi</h1>
<StateComponent value={this.state.count} />
<button onClick={this.handleClick}> click </button>
</div>
);
}
}
export default App;
6. shouldComponentUpdate
- 다음 받아올 props, state 값을 가져옴
- return 값에 따라 값의 업데이트 여부가 결정됨 ( true : 업데이트 , false : 안함 )
- 특정 조건에서 update 를 막아줄 수 있는 함수
7. componentWillUpdate
- 사용하지 않음
8. getSnapshotBeforeUpdate
- update 되기 바로 직전 DOM 상태를 return
- 직전 상태 (스크롤 위치 등) 를 componentDidUpdate 를 통해서 유지 시킬 수 있다.
9. componentDidUpdate
- getSnapshotBeforeUpdate 에서 획득한 이전 상태를 3번째 파라미터로 받아 작업 진행
10. componentWillUnmount
- component 가 사라질 때 호출됨
* sample : count 가 10이 넘어가면 StateComponent 를 더이상 표시하지 않게되고
StateComponent 가 사라지면 StateComponent 클래스에 구현된 componentWillUnmount 에 의해 특정 로직이 수행됨
[App.js]
render() {
return (
<div>
<h1>hi</h1>
{ this.state.count < 10 && <StateComponent value={this.state.count} /> }
<button onClick={this.handleClick}> click </button>
</div>
);
}
11. componentDidCatch
- component 에서 에러가 발생했을 때 확인할 수 있음
- render 함수 안에서 에러가 나면 app 자체가 crash 발생함
- 에러를 캐치하기 위해서는 자식 component 에서는 불가능하고 부모 component 에서만 가능하다
(12번 영상)
주제 : 필요 도구 설치
* 개발환경 설정
1. Node.js 설치 (webpack, babel 을 사용하기 위해 필요)
- NVM (Node Version Manager) 사용하면 편하다 (추천) : https://github.com/creationix/nvm
2. yarn 사용 : https://yarnpkg.com/en/docs/install#windows-stable
- Node.js 를 설치하면 기본적으로 NPM 이 설치되지만, 대신 yarn 을 사용하는걸 추천.
- NPM 보다 좀더 개선된 버전이라고 보면 됨.
3. IDE
- 익숙한것 사용하기
- vscode : https://code.visualstudio.com/
4. git : https://gitforwindows.org/
- 형상관리
자세한 설치방법은 추후 업데이트
(13번 영상)
주제 : create react app 사용
1. 설치 확인
- Node.js 버전 확인 : $ node -v
- yarn 버전 확인 : $ yarn -v
2. create-react-app 설치 : https://github.com/facebook/create-react-app
- 페이스북에서 만든 react 프로젝트를 통합 설치해주는 툴
- webpack, babel 설치 및 설정을 간소화 시켜줌
설치
$ npm install -g create-react-app
$ create-react-app hello-react
or
$ npx create-react-app my-app
* 프로젝트가 생성되면 개발을 시작해보자!
14번
15번
[배열에 데이터 삽입하기]
(참고)
* 자식 컴포넌트에서 부모 컴포넌트로 값 전달하기
1. 부모 컴포넌트에서 handleCreate 라는 메소드를 만들고 자식 컴포넌트로 props 로 전달한다.
2. 자식 컴포넌트에서 props 로 전달받은 handleCreate 메소드를 호출해서 데이터가 부모 컴포넌트로 전달되도록 한다.
* 기본 form 속성으로 버튼 type 이 submit 일 경우 클릭하면 페이지가 새로고침 된다.
해당 새로고침을 방지하기 위해 handleSubmit 함수를 작성해준다.
* 리액트에서는 불변성을 꼭 유지해 줘야한다.
* 어떤 값을 수정할때는 꼭 setState 를 사용해야하며, 그 내부의 배열이나 객체를 수정해야 할 때는
기존 배열, 객체를 수정하지 않고 원본을 기준으로 새로운 배열, 객체를 만들어서 값을 주입해 주어야 함.
* 배열에 추가하는 방식은 concat 사용 (C 언어에서 문자열 이어붙이기와 같은 명령어)
* 배열에 고유한 id 값이 증가하면서 추가되도록 할 때는
1. '... spread 전개 연산자'를 사용
2. 기존 속성 값을 그대로 입력
3. object.assign 객체 사용
* state 에 변수를 선언하는 이유는, render 함수에서 사용하면서 변수가 수정되었을 때 꼭 rerender 되게끔 만들게 하기 위함
[App.js - 새로고침 방지]
handleSubmit = (e) => {
e.preventDefault();
this.props.onCreate(this.state);
this.setState({
name: '',
phone: '',
})
}
[자식 컴포넌트]
- 부모 컴포넌트로 props 전달
[App.js - 배열에 고유 id 값 증가 방법]
1)
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
...data,
id: this.id++,
})
});
}
2)
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
name: data.name,
phone: data.phone,
id: this.id++,
})
});
}
3)
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat( Object.assign({}, data, {
id: this.id++
}))
});
}
16번
[자바스크립트 배열 내장 함수 - map]
(참고)
* 기본 배열 선언 :
numbers
= [1,2,3];
* map 사용 : squared = numbers.map(n => n * n);
* 사용 -> squared : [1, 4, 9] -> 기존 numbers 배열을 제곱으로 만들어줌
- defaultProps 지정해 줄때는 항상 static 으로 선언해야 한다.
* 배열에서 키가 없다면 리스트 항목을 추가 제거할 때 매우 비효율적으로 동작한다.
[PhoneInfoList.js]
render() {
const { data } = this.props;
const list = data.map(
info => (<PhoneInfo info={info} key={info.id} />)
);
return (
<div>
{list}
</div>
);
}
17번
[배열 조작]
(참고)
* 배열은 항상 불변성을 유지해야 한다.
* slice 와 concat 을 혼합해서 배열의 중간 값만 제거할 수 있다.
* 제거 방법
1) slice : 파라미터 (a,b) - a번째에서 시작해서 b번째 까지만 가져온다
2) filter : 조건으로 값을 가져올 수 있다. - 기존 배열을 변경하지 않는다.
ex) slice
ex) filter
[App.js]
handleRemove = (id) => {
const { information } = this.state;
this.setState({
information: information.filter(info => info.id !== id)
});
}
1
(18번 영상)
[배열 안의 데이터 수정하기]
* 일반적인 데이터 수정 방법 2가지
[
...numbers.slice(0,2),
9,
...numbers.slice(3,5)
]
numbers.map(n => {
if (n == 3) {
return 9;
}
})
(19번 영상)
[shouldComponentUpdate 를 통한 최적화. 불변성을 왜 유지하는가?]
(참고)
Immutable.js : https://facebook.github.io/immutable-js/
Immer.js : https://github.com/mweststrate/immer
* 중첩된 render 가 호출되면 변하지 않는 항목이 다시 render 되는 불필요한 상황이 발생한다
* shouldComponentUpdate 를 통해 방지 할 수 있다.
* 배열, 객체는 call by reference 이므로 하나의 변수를 다른 변수에 동일하게 지정하도록 하면 하나를 변경하면 둘 모두 변경된다.
ex) a = [0,1,2]
b = a
b.push(3)
b = [0,1,2,3]
a = [0,1,2,3]
* 이럴때는 지정이 아닌 새로운 변수로 만들어지도록 해야한다.
ex) a = [0,1,2]
b = [...a, 3]
이러한 객체나 배열이 길어지거나 깊어지면 복잡해지는데, 이럴 때 사용하기 좋은 라이브러리가 있다. (참고 확인)
(20번 영상)
[이름으로 전화번호 찾기]
* keyword state 를 추가하고 render 안에서 PhoneInfoList 컴포넌트의 data 속성에 바로 filter 기능을 넣어 검색 가능하도록 만든다
(21번 영상)
[Ref 를 통하여 DOM 에 직접 접근하기
* Ref 사용법 2가지
1) 함수 사용 : 태그 속성에 ref 함수를 작성. id 를 지정해주는 것과 비슷한듯
2) (react 16.3 버전 이상에서만 가능)
상단에 id 설정해 줄때 React.createRef() 를 사용한다
focus 를 호출할 때는 1번과 다르게 이름 뒤에 current 를 꼭 붙여줘야한다.
input1 = null
input2 = React.createRef();
handleSubmit = (e) => {
e.preventDefault();
this.props.onCreate(this.state);
this.setState({
name: '',
phone: '',
});
// this.input1.focus()
this.input2.current.focus();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
name="name"
placeholder="이름"
onChange={this.handleChange}
value={this.state.name}
ref={this.input2}
// ref={ref => this.input1 = ref}
/>
<input
name="phone"
placeholder="전화번호"
onChange={this.handleChange}
value={this.state.phone}
/>
<button type="submit">등록</button>
</form>
);
}
(22번 영상)
[마치면서]
추천)
1. prettier : 코드 정리
2. 리액트 컴포넌트 스타일링 : css, sass 스타일 컴포넌트를 쉽게 사용할수 잇음
3. immutable.js : 불변성 변수 사용
4. immer.js : 3번과 비슷한데 엄청 비슷
5. 리덕스 : 데이터 관리 시 update 로직을 다른 파일로 분리, 컴포넌트 등 프로젝트 구조를 체계적으로 만들 수 있음
상태 관리 라이브러리
6. 몹X 라이브러리 : 리덕스랑 비슷? 찾아봐야함
7. 리액트 라우터 v4 : 여러 페이지로 프로젝트를 구성해야 할 때
8. 타입스크립트 : 컴포넌트를 더 확실하게 사용하고 싶을때
9. Jest, Enzyme : 테스트 코드 개발 시 사용