3.1 클래스형 컴포넌트
- 클래스형 컴포넌트와 함수 컴포넌트의 차이점은 클래스형 컴포넌트의 경우 state 기능 및 라이프 사이클 기능을 사용할 수 있다는 것과 임의 메서드를 정의할 수 있다는 것이다.
- 함수 컴포넌트의 장점은 클래스형 컴포넌트보다 선언하기가 훨씬 편하다.
- 또한, 메모리 자원도 클래스형 컴포넌트보다 덜 사용하며, 프로젝트를 완성하여 빌드한 후 배포할 때도 함수 컴포넌트를 사용하는 것이 결과물의 파일 크기가 더 작다.
- 함수 컴포넌트의 주요 단점은 state와 라이프사이클 API의 사용이 불가능하다는 점이었으나, 리액트 v16.8 업데이트 이후 Hooks라는 기능이 도입되면서 해결되었다.
3.3 props
- props는 properties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소이다.
- props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정할 수 있다.
1️⃣ props 기본값 설정 : defaultProps
- defaultProps는 props 값을 따로 지정하지 않았을 때 보여 줄 기본값을 설정하는 것을 말한다.
const MyComponent = props => {
return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>
}
MyComponent.defaultProps = {
name = "기본 이름"
};
2️⃣ 태그 사이의 내용을 보여 주는 children
- 리액트 컴포넌트를 사용할 때 컴포넌트 태그 사이의 내용을 보여 주는 props인 children이 있다.
import MyComponent from "./MyComponent";
const App = () => {
return <MyComponent>리액트</MyComponent>
}
export default App;
const MyComponent = props => {
return (
<div>
안녕하세요, 제 이름은 {props.name}입니다.<br/>
children 값은 {props.children}입니다.
</div>
)
}
3️⃣ 비구조화 할당 문법을 통해 props 내부 값 추출하기
- props 값을 조회할 때마다 props.name, props.children 과 같이 props라는 키워드를 앞에 붙여 준다.
- 더 편하게 하기 위해 ES6의 비구조화 할당 문법을 사용하여 내부 값을 바로 추출하는 방법을 사용한다.
const MyComponent = props => {
const {name, children} = props;
return(
<div>
안녕하세요, 제 이름은 {name} 입니다.<br/>
childen 값은 {children}입니다.
</div>
)
}
- 객체에서 값을 추출하는 문법을 비구조화 할당이라고 부르며 구조 분해 문법이라고도 불린다.
- 함수의 파라미터 부분에서도 사용할 수 있다. 함수의 파라미터가 객체라면 그 값을 바로 비구조화해서 사용한다.
const MyComponet = ({name, children}) => {
return(
<div>
안녕하세요, 제 이름은 {name}입니다.<br/>
children 값은 {children}입니다.
</div>
)
}
4️⃣ propTypes를 통한 props 검증
- 컴포넌트의 필수 props를 지정하거나 props의 타입을 지정할 때는 propTypes를 사용한다.
import PropTypes from "prop-types";
(...)
MyComponent.propTypes = {
name: PropTypes.string
}
👌 isRequired를 사용하여 필수 propTypes 설정
- propTypes를 지정하지 않았을 때 경고 메시지를 띄워 주는 작업, propTypes를 지정할 때 뒤에 isRequired를 붙여 주면 된다.
MyCompoent.propTypes = {
name: PropTypes.string,
favoriteNumber: PropTypes.number.isRequired
}
👌 더 많은 PropTypes 종류
- array: 배열
- arrayOf(다른 propType): 특정 PropType으로 이루어진 배열, arrayOf(PropType.number)는 숫자로 이루어진 배열
- bool: true 혹은 false
- func: 함수
- number: 숫자
- object: 객체
- string: 문자열
- symbol: ES6의 Symbol
- node: 렌더링할 수 있는 모든 것(숫자, 문자열 혹은 JSX모드, children도 node PropType)
- instanceOf(클래스): 특정 클래스의 인스턴스(ex. instanceOf(MyClass))
- oneOf(["dog", "cat"]): 주어진 배열 요소 중 값 하나
- oneOfType([React.PropTypes.string, PropTypes.number]): 주어진 배열 안의 종류 중 하나
- objectOf(React.PropTypes.number): 객체의 모든 키 값이 인자로 주어진 PropType인 객체
- shape({ name: PropTypes.string, num: PropTypes.number }): 주어진 스키마를 가진 객체
- any: 아무 종류
5️⃣ 클래스형 컴포넌트에서 props 사용하기
- 클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 된다.
const { name, favoriteNumber, children } = this.props // 비구조화 할당
- 클래스형 컴포넌트에서 defaultProps와 propTypes를 설정할 때 class 내부에서 지정하는 방법도 있다.
3.4 state
- 리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다.
- props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다.
- props를 바꾸려면 부모 컴포넌트에서 바꾸어 주어야 한다.
1️⃣ 클래스형 컴포넌트의 state
constructor(props){
super(props);
// state의 초깃값 설정하기
this.state = {
number: 0
}
}
- 클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해 주어야 한다.
- 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Componet 클래스가 지닌 생성자 함수를 호출해 준다.
- this.state 값에 초깃값을 설정해 준다. 컴포넌트의 state는 객체 형식이어야 한다.
render(){
const { number } = this.state // state를 조회할 때는 this.state로 조회한다.
return(
<div>
<h1>{number}</h1>
<button>
//onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정한다.
onClick={() => {
// this.setState를 사용하여 state에 새로운 값을 넣을 수 있다.
this.setState({number: number + 1});
}}
+1
</button>
</div>
)
}
👌 state를 constructor에서 꺼내기
class Counter extends Component {
state = {
number: 0,
fixedNumber: 0
}
render(){
const {number, fixedNumber} = this.state // state를 조회할 때는 this.state로 조회한다.
return (...);
}
}
- 위처럼 사용할 경우 constructor 메서드를 선언하지 않고도 state 초깃값을 설정할 수 있다.
👌 this.setState에 객체 대신 함수 인자 전달하기
this.setState((prevState, props) => {
return {
// 업데이트하고 싶은 내용
}
})
- prevState는 기존 상태이고 props는 현재 지니고 있는 props를 가리킨다.
- 업데이트 하는 과정에서 props가 필요하지 않다면 생략해도 된다.
<button>
onClick={() => {
this.setState(prevState => {
return {
number: prevState.number + 1
}
})
// 위 코드와 아래 코드는 똑같은 기능을 한다.
// this.setState(prevState => ({
number: prevState.number + 1
}))
}}
</button>
👌 this.setState가 끝난 후 특정 작업 실행하기
- setState를 사용하여 값을 업데이트하고 난 다음에 특정 작업을 하고 싶을 때는 setState의 두 번째 파라미터로 콜백 함수를 등록하여 작업을 처리할 수 있다.
<button>
onClick={() => {
this.setState(
{
number: number + 1
}, () => {
console.log("setState 호출")
}
)
}}
+1
</button>
2️⃣ 함수 컴포넌트에서 useState 사용하기
👌 배열 비구조화 할당
- 배열 안에 들어 있는 값을 쉽게 추출할 수 있도록 해 주는 문법이다.
const array = [1, 2];
const [one, two] = array;
👌 useState 사용하기
- 클래스형 컴포넌트에서의 state 초기값을 객체 형태를 넣어 주어야 한다.
- useState에서는 반드시 객체가 아니어도 상관없으며 값의 형태는 자유이다.
- 함수를 호출하면 배열이 반환되는데, 배열의 첫 번째 원소는 현재 상태이고 두 번째 원소는 상태를 바꾸어 주는 함수이다. 이 함수를 세터 함수라고부른다.
3.5 state를 사용할 때 주의 사항
- state 값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 한다.
- 배열이나 객체를 업데이트해야 할 때는 배열이나 객체 사본을 만들고 그 사본에 값을 업데이트한 후, 그 사본의 상태를 setState 혹은 세터 함수를 통해 업데이트해야 한다.
// 객체 다루기
const object = { a: 1, b: 2, c: 3}
const nextObject = {...object, b: 2}; // 사본을 만들어서 b 값만 덮어 쓰기
// 배열 다루기
const array = [
{ id: 1, value: true},
{ id: 2, value: true},
{ id: 3, value: false}
]
let nextArray = array.concat({ id: 4}) // 새 항목 추가
nextArray.filter(item => item.id !== 2); // id가 2인 항목 제거
// id가 1인 항목의 value를 false로 설정
nextArray.map(item => (item.id === 1 ? { ...item, value: false} : item));
- 객체에 대한 사본을 만들 때는 spread 연산자라 불리는 ...을 사용하여 처리하고 배열에 대한 사본을 만들 때는 배열의 내장 함수들을 활용한다.
#출처 : 리액트를 다루는 기술(저자 : 김민준 VELOPERT)
'Front-End, CS 스터디 > [도서] 리액트를 다루는 기술' 카테고리의 다른 글
[도서] 리액트를 다루는 기술 #JSX (0) | 2022.11.11 |
---|---|
[도서] 리액트를 다루는 기술 #컴포넌트의 라이프사이클 메서드 (0) | 2022.11.09 |
[도서] 리액트를 다루는 기술 #컴포넌트 성능 최적화 (0) | 2022.11.07 |
[도서] 리액트를 다루는 기술 #Hooks (0) | 2022.11.05 |
[도서] 리액트를 다루는 기술 #서버 사이드 렌더링 (2) | 2022.11.01 |