컴포넌트를 선언하는 방식은 두가지 입니다.
1. 함수 컴포넌트
2. 클래스형 컴포넌트
함수 컴포넌트는 코드가 다음과 같은 구조로 이루어져 있습니다.
import './App.css';
function App(){
const name = '리액트';
return <div className=:"react">{name}</div>;
}
export default App;
클래스형 컴포넌트는 코드가 다음과 같은 구조로 이루어져 있습니다.
import { Component } from 'react';
class App extends Component {
render() {
const name = '리액트';
return <div className=:"react">{name}</div>;
}
}
export default App;
클래스형 컴포넌트와 함수 컴포넌트의 차이점은 클래스형 컴포넌트의 경우 이후 배울 state 기능 및 라이프 사이클 기능을 사용할 수 있다는 것과 임의 메서드를 정의할 수 있다는 것입니다.
클래스형 컴포넌트에서는 render 함수가 꼭 있어야 하고, 그 안에서 보여줘야할 JSX를 반환해야합니다.
const MyConponent = () => {
return <div><h1>나의 첫 컴포넌트</h1></div>;
};
export default MyComponent;
export default MyComponent;
import MyComponent from './MyComponent';
const App = () => {
return <MyComponent />
};
export default App;
props는 properties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소입니다. Props 값은 해당 컴포넌트를 불러와 사용하는 부모 커모넌트에서 설정할 수 있습니다.
name이라는 props를 렌더링하도록 설정해봅시다. props 값은 컴포넌트 함수의 파라미터로 받아와서 사용할 수 있습니다.
const MyComponent = props => {
return <div><h1>안녕하세요, 제 이름은 {props.name}입니다.</h1></div>;
}
export default MyComponent;
import MyComponent from './MyComponent';
const App = () => {
return <MyComponent name="React" />;
}
export default App;
const MyComponent = props => {
return <div><h1>안녕하세요, 제 이름은 {props.name}입니다.</h1></div>;
}
MyComponent.defaultProps = {
name : '기본 이름'
}
export default MyComponent;
App.js
import MyComponent from "./MyComponent";
const App = () => {
return <MyComponent>리액트</MyComponent>;
};
export default App;
MyComponent.js
const MyComponent = (props) => {
return (
<div>
<h1>
안녕하세요, 제 이름은 {props.name}입니다.
<br />
children 값은 {props.children} 입니다.
</h1>
</div>
);
};
MyComponent.defaultProps = {
name: "기본 이름",
};
export default MyComponent;
MyComponent에서 props 값을 조회할 때마다 props.name, props.children과 같이 props 라는 키워드를 붙여주고 있습니다.
ES6의 비구조화 할당 문법을 사용하여 내부 값을 바로 추출하는 방법을 알아보겠습니다.
MyComponent.js
const MyComponent = (props) => {
const { name, children } = props;
return (
<div>
<h1>
안녕하세요, 제 이름은 {name}입니다.
<br />
children 값은 {children} 입니다.
</h1>
</div>
);
};
MyComponent.defaultProps = {
name: "기본 이름",
};
export default MyComponent;
더 간단하게 줄이는 방법도 존재합니다.
MyComponent.js
const MyComponent = ({ name, children }) => {
return (
<div>
<h1>
안녕하세요, 제 이름은 {name}입니다.
<br />
children 값은 {children} 입니다.
</h1>
</div>
);
};
MyComponent.defaultProps = {
name: "기본 이름",
};
export default MyComponent;
컴포넌트 필수 props를 지정하거나 props 타입을 지정할 때는 propTypes를 사용합니다.
MyComponent.js
import PropTypes from "prop-types";
const MyComponent = ({ name, children }) => {
return (
<div>
<h1>
안녕하세요, 제 이름은 {name}입니다.
<br />
children 값은 {children} 입니다.
</h1>
</div>
);
};
MyComponent.defaultProps = {
name: "기본 이름",
};
MyComponent.protoTypes = {
name: PropTypes.string,
};
export default MyComponent;
이렇게 설정해주면 name의 값은 무조건 문자열(string)형태로 전달해야 된다는 것을 의미합니다.
MyComponent.js
import PropTypes from "prop-types";
const MyComponent = ({ name, favoriteNumber, children }) => {
return (
<div>
<h1>
안녕하세요, 제 이름은 {name} 입니다.
<br />
children 값은 {children} 입니다.
<br />
제가 좋아하는 숫자는 {favoriteNumber} 입니다.
</h1>
</div>
);
};
MyComponent.defaultProps = {
name: "기본 이름",
};
MyComponent.protoTypes = {
name: PropTypes.string,
favoriteNumber: PropTypes.number.isRequired,
};
export default MyComponent;
App.js
import MyComponent from "./MyComponent";
const App = () => {
return (
<MyComponent name="React" favoriteNumber={11}>
리액트
</MyComponent>
);
};
export default App;
클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 됩니다.
MyComponent.js
import { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const { name, favoriteNumber, children } = this.props; //비구조화 할당
return (
<div>
<h1>
안녕하세요, 제 이름은 {name} 입니다.
<br />
children 값은 {children} 입니다.
<br />
제가 좋아하는 숫자는 {favoriteNumber} 입니다.
</h1>
</div>
);
}
}
MyComponent.defaultProps = {
name: "기본 이름",
};
MyComponent.protoTypes = {
name: PropTypes.string,
favoriteNumber: PropTypes.number.isRequired,
};
export default MyComponent;
클래스형 컴포넌트에서 defaultProps와 propTypes를 설정할 때 Class 내부에서 지정하는 방법도 있습니다.
MyComponent.js
import { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
static defaultProps = {
name: "기본 이름s",
};
static propTypes = {
name: PropTypes.string,
favoriteNumber: PropTypes.number.isRequired,
};
render() {
const { name, favoriteNumber, children } = this.props; //비구조화 할당
return (
<div>
<h1>
안녕하세요, 제 이름은 {name} 입니다.
<br />
children 값은 {children} 입니다.
<br />
제가 좋아하는 숫자는 {favoriteNumber} 입니다.
</h1>
</div>
);
}
}
export default MyComponent;
state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미합니다.
props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있습니다.
클래스형 컴포넌트의 state를 이해하기 위해 src/Counter.js 파일을 생성합니다.
Counter.js
import { Component } from "react";
class Counter extends Component {
constructor(props) {
super(props);
//state의 초깃값 설정하기
this.state = {
number: 0,
};
}
render() {
const { number } = this.state; //state를 조회할 때는 this.state로 조회합니다.
return (
<div>
<h1>{number}</h1>
<button
//on Click을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
onClick={() => {
//this.setState 를 사용하여 state에 새로운 값을 넣을 수 있습니다.
this.setState({ number: number + 1 });
}}
>
+1
</button>
</div>
);
}
}
export default Counter;
컴포넌트에 state를 설정할 때는 위와 같이 constructor 메서드(컴포넌트의 생성자 메서드)를 작성하여 설정합니다. 클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해줘야 합니다. 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해줍니다.
App.js
import Counter from "./Counter";
const App = () => {
return <Counter />;
};
export default App;
Counter.js
import { Component } from "react";
class Counter extends Component {
constructor(props) {
super(props);
//state의 초깃값 설정하기
this.state = {
number: 0,
fixedNumber: 0,
};
}
render() {
const { number, fixedNumber } = this.state; //state를 조회할 때는 this.state로 조회합니다.
return (
<div>
<h1>{number}</h1>
<h1>바뀌지 않는 값 : {fixedNumber}</h1>
<button
//on Click을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
onClick={() => {
//this.setState 를 사용하여 state에 새로운 값을 넣을 수 있습니다.
this.setState({ number: number + 1 });
}}
>
+1
</button>
</div>
);
}
}
export default Counter;
Counter.js
import { Component } from "react";
class Counter extends Component {
state = {
number: 0,
fixedNumber: 0,
};
render() {
const { number, fixedNumber } = this.state; //state를 조회할 때는 this.state로 조회합니다.
return (...);
}
}
export default Counter;
this.setState를 사용하여 state값을 업데이트할 때는 상태가 비동기적으로 업데이트 됩니다. 이에 대한 해결책은 this.setState를 사용할 떄 객체 대신 함수를 인자로 넣어주는 것입니다.
this.setState((prevState, props) =>{
return{
//업데이트하고 싶은 내용
}
})
setState를 사용하여 값을 업데이트하고 난 다음에 특정 작업을 하고 싶을떄는 setState의 두번째 파라미터로 콜백 함수를 등록하여 작업을 처리할 수 있습니다.
const array = [1,2]; => const array = [1,2];
const one = array[0]; const [one,two] = array;
const two = array[1];
Say.js
import { 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;
Say.js
import { 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;
props와 state 는 둘 다 컴포넌트에서 사용하거나 렌더링할 데이터를 담고 있으므로 비슷해보일 수 있지만 역할은 매우 다릅니다.
리액트를 다루는 기술 [개정판] (김민준, 길벗출판사) 책을 참고하였습니다.