[React] component, props, state
컴포넌트
- 앱을 이루는 최소한의 단위
- 컴포넌트에는 클래스형 컴포넌트와 함수형 컴포넌트가 존재
클래스형 컴포넌트
class App extends Component {
render() {
const name = "리액트";
return <div className="react">{name}</div>;
}
}
함수형 컴포넌트
// 일반 함수
function App() {
const name = '리액트';
return <div className="react">{name}</div>;
}
// 화살표 함수
const App = () => {
const name = '리액트';
return <div className="react">{name}</div>;
}
[참고] 일반 함수와 화살표 함수의 this
두 컴포넌트의 차이점
- 클래스형 컴포넌트는 state와 라이프사이클 API 사용 가능
- 함수형 컴포넌트는 state와 라이프사이클 API 사용 불가능 → (리액트 v16.8 업데이트) Hooks 기능 도입
리액트 공식 매뉴얼에서는 함수형 컴포넌트와 Hooks사용을 권장
props
- properties의 약자
- 컴포넌트의 속성을 설정할 때 사용
- props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정 가능
JSX 내부에서 props 렌더링
- props 값은 컴포넌트 함수의 파라미터로 받아 와서 사용 가능
- props를 렌더링할 때 JSX 내부에서 { }기호로 감싸주면 됨
// props 값 지정
const App = () => {
return <MyComponent name="React" />;
};
const MyComponent = props => {
return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>;
};
props 디폴트 값 지정
MyComponent.defaultProps = {
name: '기본 이름'
};
태그 사이 내용 보여주기
const App = () => {
return <MyComponent>리액트</MyComponent>;
};
const MyComponent = props => {
return (
<div>
안녕하세요, 제 이름은 {props.name}입니다.<br />
children 값은 {props.children}입니다.
</div>
);
};
결과
안녕하세요, 제 이름은 기본 이름입니다.
children 값은 리액트입니다.
props 구조 분해
props 값을 조회할 때 마다 앞에 props 키워드 붙이는 것은 번거로움
→ 구조 분해(비구조화 할당)을 이용하여 내부 값을 바로 추출 가능
const MyComponent = props => {
const {name, children} = props;
return (
<div>
안녕하세요, 제 이름은 {name}입니다.<br />
children 값은 {children}입니다.
</div>
);
};
혹은
const MyComponent = ({name, children}) => {
return (
<div>
안녕하세요, 제 이름은 {name}입니다.<br />
children 값은 {children}입니다.
</div>
);
};
propTypes
- 필수 props를 지정하거나 props의 타입을 지정할 때 사용
아래처럼 지정시 name은 무조건 문자열 형태로 전달해야 된다는 것을 의미
필수 props는 isRequired를 붙여서 지정
MyComponent.propTypes = {
name: PropTypes.string,
favoriteNumber: PropTypes.number.isRequired
};
※ 클래스형 컴포넌트에서 props를 사용할 때는 render함수에서 this.props를 조회하면 됨
State
- 컴포넌트 내부에서 바뀔 수 있는 값
📎 props
- 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값
- 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용 가능
- props를 변경하기 위해서는 부모 컴포넌트에서 바꾸어 주어야 함
- 두 가지 종류의 state
- 클래스형 컴포넌트가 지니고 있는 state
- 함수형 컴포넌트에서 useState 함수를 통해 사용하는 state
클래스형 컴포넌트의 state
import React, { Component } from 'react';
class Counter extends Component {
// part1
constructor(props) {
super(props);
this.state = {
number: 0;
};
}
// part2
render() {
const { number } = this.state;
return (
<div>
<h1>{number}</h1>
<button
onClick={() => {
this.setState({ number: number + 1});
}}
>
+1
</button>
</div>
);
}
}
export default Counter;
# part1
constructor(props) {
super(props);
this.state = {
number: 0;
};
}
- 클래스형 컴포넌트에서 constructor(생성자)를 작성할 때는 반드시 super(props)를 호출해야 함
- → 현재 클러스터형 컴포넌트가 상속하고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출
- this.state 값에 초깃값을 설정 (클래스형 컴포넌트의 state는 객체 형식이어야 함
constructor 사용 안하고 state초기값 설정하는 방식
state = {
number: 0,
fixedNumber: 0
};
# part2
render() {
const { number } = this.state; // state 를 조회 할 때에는 this.state 로 조회합니다.
return (
<div>
<h1>{number}</h1>
<button
onClick={() => {
this.setState({ number: number + 1});
}}
>
+1
</button>
</div>
);
}
- button 안에 onClick(버튼이 클릭될 때 호출할 함수를 설정하는 이벤트) props
- 이벤트로 설정할 함수를 넣어줄 때는 화살표 함수 문법 사용
- this.setState는 state 값을 바꿀 수 있게 해줌
this.setState에 함수 전달
this.setState를 사용하여 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트 됨
코드를 아래와 같이 작성한다고 해서 버튼을 클릭할 때 숫자가 2씩 더해지진 않는다는 소리
onClick={() => {
this.setState({ number: number + 1});
this.setState({ number: this.state.number + 1 });
}}
→ 객체 대신에 함수를 인자로 넣어서 해결
onClick={() => {
this.setState(prevState => ({
number: prevState.number + 1
}));
}}
this.setState가 끝난 후 특정 작업 실행
setState의 두 번째 파라미터로 콜백 함수를 등록하여 작업 처리 가능
onClick={() => {
this.setState(
{ number: number + 1 },
() => {
console.log('방금 setState가 호출되었습니다.');
console.log(this.state);
}
);
}}
함수형 컴포넌트의 state
리액트 16.8 이후부터는 useState라는 함수를 사용하여 함수형 컴포넌트에서도 state를 사용할 수 있게 되었음
import React, { useState } from 'react';
const Say = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage('안녕하세요!');
const onClickLeave = () => setMessage('안녕히 가세요!');
const [color, setColor] = useState('black');
return (
<div>
<button onClick={onClickEnter}>입장</button>
<button onClick={onClickLeave}>퇴장</button>
<h1 style={{ color }}>{message}</h1>
<button style={{ color: 'red' }} onClick={() => setColor('red')}>빨간색</button>
<button style={{ color: 'green' }} onClick={() => setColor('green')}>초록색</button>
<button style={{ color: 'blue' }} onClick={() => setColor('blue')}>파란색</button>
</div>
);
};
export default Say;
- useState의 인자에는 상태의 초기값 (클래스형 컴포넌트와 달리 반드시 객체가 아니어도 됨)
- useState는 배열을 반환
- 배열의 첫 번째 원소는 현재 상태, 두 번째 원소는 상태를 바꿔주는 함수(setter)
state 사용시 주의 사항
state 값을 바꿀 때는 반드시 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 함
→ 배열이나 객체를 업데이트 해야할 때는 사본을 만들어서 값을 업데이트하는 방식 사용
- 배열의 사본은 배열 내장 함수 이용 (filter, map 등)
- 객체의 사본은 spread 연산자 이용
정리
props는 부모 컴포넌트가 설정
state는 컴포넌트 자체적으로 지닌 값 → 컴포넌트 내부에서 값 업데이트 가능
하지만 props를 사용한다고 해서 값이 무조건 고정적인 것은 아님
부모 컴포넌트의 state를 자식 컴포넌트의 props로 전달하고, 자식 컴포넌트에서 특정 이벤트가 발생할 때 부모 컴포넌트의 메소드를 호출하면 props도 유동적으로 사용 가능
📌 아래 문서와 서적의 내용을 정리한 글입니다.