3.1 클래스형 컴포넌트
클래스형 컴포넌트 특징
- state 기능 및 라이프사이클 기능을 사용할 수 있음
- 임의 메서드를 정의할 수 있음.
- render 함수가 꼭 있어야 함.
함수형 컴포넌트 특징
- 클래스형 컴포넌트보다 선언하기 편함
- 메모리 자원을 클래스형 컴포넌트보다 덜 사용함.
- 빌드 후 배포할 때도 클래스형 컴포넌트와 비교했을 때 결과물의 크기가 더 작음.
- state 및 라이프사이클 API를, Hooks라는 기능을 통해 간접 구현( v16.8)
- 리액트 공식 매뉴얼에서 함수형 컴포넌트와 Hooks를 사용하도록 권장.
1.함수형
import React from "react";
import './App.css';
function App() {
const name = '리액트';
return <div className="react">{name}</div>
}
export default App;
2.클래스형
import React, {Component} from "react";
import './App.css';
class App extends Component {
render() {
const name = 'react';
return <div className="react">{name}</div>
}
}
export default App;
3.2 첫 컴포넌트 생성
//화살표 함수로 함수형 컴포넌트 구현
import React from "react";
const MyComponent = () => {
return <div>화살표형 함수로 컴포넌트 구현</div>;
};
export default MyComponent;
일반 함수 vs 화살표형 함수
- 화살표형 함수가 일반 함수를 완전히 대체할 수 있을까? (X) 둘의 용도가 다르므로 완전 대체는 불가능함.
(화살표 함수는 주로 함수를 파라미터로 전달할 때 유용) - 함수 안에서 this를 호출했을 때 일반 함수는 자신이 종속된 객체를 가리키며, 화살표 함수는 자신이 종속된 인스턴스를 가리킴.
- 화살표 함수는 값을 연산하여 바로 반환해야 할 때 사용하면 가독성을 높일 수 있음.
(따로 { } 를 열어주지 않으면 연산한 값을 그대로 반환)
ex> function twice(value) {return value*2}; ===> const triple = (value) => value*3;
1.일반 함수에서의 this
function BlackDog() {
this.name = '흰둥이';
return {
name: '검둥이',
bark: function () {
console.log(this.name + ': 멍멍!');
}
}
}
const blackDog = new BlackDog();
blackDog.bark(); //검둥이: 멍멍!
2.화살표 함수에서의 this
function WhiteDog() {
this.name = '흰둥이';
return {
name: '검둥이',
bark: () => {
console.log(this.name + ': 멍멍!');
}
}
}
const whiteDow = new WhiteDog();
whiteDow.bark(); //흰둥이: 멍멍!
3.3 props
3.3.1 JSX 내부에서 props 랜더링
import React from "react";
const MyComponent = props => {
return <div>안녕하세요, 제 이름은 {props.name} 입니다.</div>;
};
export default MyComponent
3.3.2 컴포넌트를 사용할 때 props값 지정하기
import React from 'react';
import MyComponent from "./MyComponent";
const App = () => {
return <MyComponent name="React"/>
}
export default App;
3.3.3 props 기본값 설정 : defaultProps
import React from "react";
const MyComponent = props => {
return <div>안녕하세요, 제 이름은 {props.name} 입니다.</div>;
};
MyComponent.defaultProps = {
name: '기본 이름'
}
export default MyComponent
3.3.4 태그 사이의 내용을 보여주는 children
1.children 전달
import React from 'react';
import MyComponent from "./MyComponent";
const App = () => {
return <MyComponent>리액트</MyComponent>
}
export default App;
2.porps로 받은 children 출력
import React from "react";
const MyComponent = props => {
return (
<div>
안녕하세요, 제 이름은 {props.name} 입니다.<br/>
children 값은 {props.children}
</div>);
};
MyComponent.defaultProps = {
name: '기본 이름'
}
export default MyComponent
3.3.5 비구조화 할당 문법을 통해 props 내부 값 추출하기
import React from "react";
const MyComponent = props => {
const {name, children} = props;
return (
<div>
안녕하세요, 제 이름은 {name} 입니다.<br/>
children 값은 {children}
</div>);
};
export default MyComponent
3.3.6 propTypes를 통한 props 검증
컴포넌트에서 설정한 props가 propsTypes에서 지정한 형태와 일치하지 않는다면 브라우저 개발자 도구의 console 탭에 경고 메시지 출력됨.
import React from "react";
import PropTypes from 'prop-types';
const MyComponent = props => {
...
};
MyComponent.propTypes = {
name : PropTypes.string,
favoriteNumber : PropTypes.number.isRequired
}
export default MyComponent
3.3.7 클래스형 컴포넌트에서 props 사용하기
Class형 컴포넌트는 render함수 내부에서 this.props를 조회. defaultProps, propTypes는 함수형 컴포넌트와 같은 방식으로 하거나 class 내부에서 지정
import React, {Component} from "react";
import PropTypes from 'prop-types';
class MyComponent extends Component {
static defaultProps = {
name: '기본 이름'
}
static propTypes = {
name: PropTypes.string
}
render() {
const {name, favoriteNumber, children} = this.props; //비구조화 할당
return (
<div>
안녕하세요, 제 이름은 {name} 입니다.<br/>
children 값은 {children}
<br/>
제가 좋아하는 숫자는 {favoriteNumber} 입니다.
</div>
);
}
}
export default MyComponent
3.4 state
3.4.1 클래스형 컴포넌트의 state
state를 설정할 때 constructor 메서드(생성자)를 사용함.
constructor를 작성할 때는 반드시 super(props)를 호출해야 함.
(클래스형 컴포넌트가 상속하고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해줌.)
1.
import React, {Component} from "react";
class Counter extends Component {
constructor(props) {
super(props);
//state의 초깃값 설정하기
this.state = {
number: 0,
fixedNumber: 0
};
}
render() {
const {number, fixedNumber} = this.state;
return (
<div>
<h1>{number}</h1>
<h2>바뀌지 않는 값 : {fixedNumber}</h2>
<button onClick={() => {
this.setState({number: number + 1});
//setState함수는 인자로 전달된 객체 안에 들어 있는 값만 바꾸어 줌.
}}>
+1
</button>
</div>
);
}
}
export default Counter;
2.constructor 메소드를 선언하지 않고, state초깃값 설정
import React, {Component} from "react";
class Counter extends Component {
state = {
number: 0,
fixedNumber: 0
};
render() {
const {number, fixedNumber} = this.state;
return (
<div>
<h1>{number}</h1>
<h2>바뀌지 않는 값 : {fixedNumber}</h2>
<button onClick={() => {
this.setState({number: number + 1});
//setState함수는 인자로 전달된 객체 안에 들어 있는 값만 바꾸어 줌.
}}>
+1
</button>
</div>
);
}
}
export default Counter;
3.this.setState에 객체 대신 함수 인자 전달
<button onClick={() => {
this.setState(prevState => {
return {number: prevState.number + 1}
});
// { } 생략해서 함수에서 값 바로 반환
this.setState(prevState => ({number: prevState.number + 1}));
}}>
+1
</button>
4.this.setState가 끝난 후 특정 작업 실행하기
<button onClick={() => {
this.setState({number: number + 1}, () => {
console.log('방금 setState가 호출되었습니다.');
console.log(this.state);
});
//setState함수는 인자로 전달된 객체 안에 들어 있는 값만 바꾸어 줌.
}}>
+1
</button>
3.4.2 함수형 컴포넌트에서 useState 사용하기
리액트 16.8이후 userState라는 함수를 사용하여 함수형 컴포넌트에서도 statef를 사용할 수 있게됨.
클래스형 컴포넌트에서의 state 초깃값은 객체 형태를 넣어줘야 하지만, useState는 값의 형태가 자유로움.
함수를 호출하면 배열이 반환됨. 첫 번째 원소는 현재 상태, 두 번째 원소는 상태를 바꿔주는 함수(세터).
배열 비구조화 할당을 통해 이름을 자유롭게 정해 줄 수 있음.
import React, {useState} from "react";
const Say = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage('안녕하세요!');
const onClickLeave = () => setMessage('안녕히 가세요!');
return (
<div>
<button onClick={onClickEnter}>입장</button>
<button onClick={onClickLeave}>퇴장</button>
<h1>{message}</h1>
</div>
);
}
export default Say;
3.5 state를 사용할 때 주의 사항
- state값을 바꾸어야 할 때 setState혹은 useState를 통해 전달받은 세터 함수를 사용해야 함.
- 배열이나 객체는 사본을 만들고 그 사본에 값을 업데이트한 후, 그 사본의 상태를 setState혹은 세터 함수를 통해 업데이트해야 함.
//객체 다루기
const object = {a: 1, b: 2, c: 3};
const newtObject = {...object, b: 2}; //사본을 만들어서 b값만 덮어 쓰기
//배열 다루기
const array = [
{id: 1, value: true},
{id: 2, value: true},
{id: 3, value: true},
];
let nextArray = array.concat({id: 4});
nextArray.filter(item => item.id !== 2);
nextArray.map(item => (item.id === 1) ? {...item, value: false}, item);
'개발 도서 > 리액트를 다루는 기술(개정판)' 카테고리의 다른 글
5장 ref:DOM에 이름 달기 (0) | 2020.05.23 |
---|---|
4장 이벤트 핸들링 (0) | 2020.05.22 |
2장 JSX (0) | 2020.05.16 |
1장 리액트 시작 (0) | 2020.05.16 |
목차 (0) | 2020.05.16 |