리액트 컴포넌트 : Property
⚠️장문주의⚠️
Property(프로퍼티)란
프로퍼티(properties, 줄여서 props)는 상위 컴포넌트가 하위 컴포넌트에 값을 전달할 때 사용하는 읽기 전용 데이터이다. 즉, 우리가 어떠한 값을 컴포넌트에 전달해줘야 할 때, props를 사용한다. props는 수정할 수 없는 읽기 전용 데이터이기 때문에 props 자체에서 입력값을 바꾸려 하면 안된다. 이 props 는 다음 장에 배울 스테이트(state)를 통해서 읽기 전용 데이터인 props를 규칙을 위반하지 않고 출력값을 변경할 수 있다.
프로퍼티의 기본 사용법
- 상위 컴포넌트에서는 컴포넌트 옆에 속성 형태로 전달할 데이터를 작성한다.
- 하위 컴포넌트에서는 전달받은 데이터를 this.props.<전달받은 변수명>
//App.js (클래스형 컴포넌트)
import React, { Component } from 'react';
import MyComponent from "./MyComponent";
class App extends Component {
render() {
return (
<div>
<MyComponent name="message"/>
</div>
);
}
}
export default App;
App.js 에서 <MyComponent /> 로 컴포넌트를 렌더링하고 그 옆에 속성 형태로 전달되는 값 name="react" 가 프로퍼티다.(사용자 정의 컴포넌트 렌더링)
//MyComponent.js (클래스형 컴포넌트)
import React, { Component } from 'react';
class MyComponent extends Component {
render() {
//App.js 에서 전달받은 property name 사용
const name = this.props.name;
return <span>{name}</span>
}
}
export default MyComponent;
하위 컴포넌트인 MyComponent.js 에서는 상위 컴포넌트 App.js 에서 전달받은 name 프로퍼티를 this.props.name으로 받아 변수에 저장하여 사용하고 있다. App 컴포넌트에서 MyComponent 컴포넌트로 " 단방향으로 " 데이터가 흐르고 있다. 단방향으로 데이터가 흐르는 것은 간단하지만 중요한 규칙이다.
//MyComponent.js (함수형 컴포넌트)
import React from 'react';
function MyComponent(props) {
return <div>안녕하세요 {props.name}</div>
}
export default MyComponent;
위 코드는 클래스형 컴포넌트가 아닌 함수형 컴포넌트로 작성한 MyComponent.js 코드이다. 함수형 컴포넌트에서는 컴포넌트 인자로 props(프로퍼티)를 받아오고 return에서 this가 없이 바로 사용할 수 있어 클래스형 컴포넌트 코드보다 간결하게 사용할 수 있다.
* 함수형 컴포넌트에 대해서는 뒤에서 더 다룰 예정으로 여기서는 클래스형 컴포넌트 코드를 사용합니다!
프로퍼티의 자료형(타입) 정의 : PropType 와 프로퍼티의 다양한 활용
형식은 리액트에서 제공하는 prop-types를 이용하여 각각의 자료형을 선언하면 된다.
PropTypes 와 함께 컴포넌트를 생성하는 단축키는 rscp (함수형), rccp (클래스형) ⭐
1) 1개의 프로퍼티 사용하기
앞서 본 방식과 같이 변수에 props를 받아서 사용할 수 있지만 " this.props.변수명 " 을 통해서 바로 사용할 수 있다. 또 프로퍼티에서는 자바스크립트의 자료형을 모두 사용 가능하다. 이때 프로퍼티의 자료형은 미리 선언해주는 것이 좋다. (권장) 프로퍼티의 자료형을 미리 선언하면 리액트 엔진이 프로퍼티로 전달하는 값의 변화를 효율적으로 감지할 수 있고, 개발자가 실수로 지정되지 않은 자료형을 프로퍼티에 전달하려고 할 때 경고 메시지로 알려주기 때문이다.
//MyComponent.js (클래스형 컴포넌트)
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class MyComponent extends Component {
render() {
return (
<div>
<div>String 대신 Number 타입을 전달</div>
<span>name : {this.props.name}</span>
</div>
);
}
}
//props 자료형 선언
MyComponent.propTypes = {
name : PropTypes.string,
};
export default MyComponent;
위 코드처럼 " <컴포넌트명>.propTypes " 에 " PropTypes.<자료형> " 으로 프로퍼티로 받은 변수들의 자료형을 정의하면 된다. 만약 정의된 자료형 외 다른 자료형의 프로퍼티를 전달하면 아래와 같이 콘솔창에 경고가 노출된다.
2) 여러 개의 다양한 프로프터 사용하기
앞서 본 코드와 같이 프로퍼티에 문자열을 전달할 때는 큰따옴표( " " )를 사용한다. 하지만 숫자형이나 불리언 등의 값을 전달할 때는 큰따옴표를 사용할 수 없다. 그래서 리액트에서 문자열 외의 값을 프로퍼티에 전달할 때는 중괄호( { } )를 사용한다.
* 코드는 MyComponent.js 코드를 수정하여 사용하겠습니다!
//App.js
import React, { Component } from "react";
import MyComponent from "./MyComponent";
class App extends Component {
render() {
const array = [1,2,3];
const obj = { name: "title", page : 30 };
const node = <span>노드</span>;
const func = () => { console.log("message"); };
return (
<div>
<MyComponent
strValue="리액트"
boolValue={true}
numValue={1}
arrayValue={array}
objValue={obj}
nodeValue={node}
funcValue={func}
/>
</div>
);
}
}
export default App;
위에서 말한대로 문자열을 프로퍼티에 전달할 때는 큰따옴표를, 나머지 자료형은 중괄호를 사용한다. 또한 실무에서는 실수를 줄이기 위해서 객체를 변수에 담아서 전달하는 방식을 선호한다. (배열, 객체, 노드, 함수 등..)
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const {
strValue,
boolValue,
numValue,
arrayValue,
objValue,
nodeValue,
funcValue,
} = this.props; // 구조분해를 이용해서 여러개의 props 값을 변수에 저장 ⭐
return (
<div>
<div>문자열값 : {strValue}</div>
<div>불리언값 : {String(boolValue)}</div>
<div>숫자값 : {numValue}</div>
<div>배열값 : {String(arrayValue)}</div>
<div>객체값 : {JSON.stringify(objValue)}</div>
<div>노드값 : {nodeValue}</div>
<div>함수값 : {String(funcValue)}</div>
</div>
);
}
}
//props 자료형 정의 ⭐
MyComponent.propTypes = {
strValue: PropTypes.string,
boolValue: PropTypes.bool,
numValue: PropTypes.number,
//배열형은 arrayOf에 어떤 자료형으로 되어있는지 적음.
arrayValue: PropTypes.arrayOf(PropTypes.number),
objValue: PropTypes.object,
nodeValue: PropTypes.node,
funcValue: PropTypes.func,
};
export default MyComponent;
여러 개의 프로퍼티를 전달할 때는 구조분해를 이용해서 프로퍼티에게 전달받은 값을 변수에 넣는 것이 유용하다.
3) 불리언 프로퍼티 사용하기
불리언(boolean) 은 true/false 만 정의할 수 있는 특수한 자료형이다. 2번에서 불리언은 중괄호로 감싸서 전달해야 한다고 했지만 특별한 방법으로 전달할 수 있다.
- 불리언 프로퍼티를 true 로 전달하는 경우 : 프로퍼티의 이름만 선언
- 불리언 프로퍼티를 false 로 전달하는 경우 : 프로퍼티의 이름을 생략
//MyComponent.js
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const message = this.props.boolValue ? "true" : "false";
return (
<div>
<div>불리언값 : {message}</div>
</div>
);
}
}
export default MyComponent;
App 컴포넌트가 MyComponent에게 boolValue 라는 프로퍼티 이름만 선언한 경우 값을 true로 전달한다. App 컴포넌트가 MyComponent 전달하는 불리언 프로퍼티를 생략한 경우 값을 false로 전달한다.
import React, { Component } from "react";
import MyComponent from "./MyComponent";
class App extends Component {
render() {
return (
<div>
<MyComponent boolValue />
<MyComponent />
</div>
);
}
}
위의 App.js 코드와 같이 변수명만 선언했을 때 true로 값이 나오고, 아예 생략했을 때 false가 나온다.
4) 객체형 프로퍼티 사용하기
객체는 여러 값을 저장할 수 있는 자료형이다. 여러 값이 저장되어 있는 객체의 구조의 프로퍼티 타입(자료형) 을 정의하는 방법 따로 있다. 프로퍼티 타입을 정의하는 블록에 <객체명> : PropTypes.shape({ }) 을 작성하고, 중괄호 안에 객체 구조와 각 객체 속성들의 자료형을 정의하면 된다.
//MyComponent.js (클래스형 컴포넌트)
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const { objValue } = this.props;
return (
<div>
{/* String(Object.entries()) 보다 JSON.stringify() 를 추천 */}
<div>객체값 : {String(Object.entries(objValue))}</div>
<div>객체값 : {JSON.stringify(objValue)}</div>
</div>
);
}
}
//props 자료형 정의
MyComponent.propTypes = {
objValue: PropTypes.shape({
name: PropTypes.string,
page: PropTypes.number,
}),
};
export default MyComponent;
objValue : PropTypes.shape() 를 이용해서 객체 프로퍼티의 세부 자료형을 정의하였다. 여기서 객체를 문자열로 보여줄 때 String(Object.entries()) 보다 JSON.stringify() 를 사용하는 것이 더 좋다. (후자는 객체 형식으로 출력된다.) 두 차이는 아래에서 볼 수 있다.
5) 프로퍼티에 필수값과 기본값 설정하기
- 필수값 설정 : 필수 프로퍼티 (꼭 전달되어야하는 프로퍼티)로 지정하여 전달한다. 필수 프로퍼티는 PropTypes에 정의된 변수 안의 특수 변수 isRequired를 이용하여 정의하면 된다. ( 필수값명 : PropTypes.자료형.isRequired )
- 기본값 설정 : propTypes와 같이 defaultProps 값을 이용하여 기본값을 지정할 변수를 " <변수명> : 기본값 " 형식으로 정의하면 된다.
//MyComponent.js 에 필수값, 기본값 설정 (코드를 자세히 봐주세요)
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const { objValue, requiredValue, defaultValue } = this.props;
return (
<div>
<div>객체값 : {JSON.stringify(objValue)}</div>
<div>필수값 : {requiredValue}</div>
<div>기본값 : {defaultValue}</div>
</div>
);
}
}
//props 자료형 정의
MyComponent.propTypes = {
objValue: PropTypes.shape({
name: PropTypes.string,
page: PropTypes.number,
}),
defaultValue: PropTypes.string,
//필수 프로퍼티 정의 ⭐
requiredValue: PropTypes.string.isRequired,
};
//기본값 선언 ⭐
MyComponent.defaultProps = {
defaultValue: "default",
};
export default MyComponent;
위에 코드를 통해서 필수 프로퍼티를 정의한다. 문자열의 필수 프로퍼티는 PropTypes.string.isRequired으로 지정했다.
또한 MyComponent.defaultProps를 통해서 defaultValue라는 변수에 기본값으로 "default" 을 설정하였다. 아래 코드를 보면 알 수 있듯이 defaultValue라는 값은 프로퍼티에서 전달하지 않았다. 하지만 사진을 보면 기본값에 default값이 들어가 있다. 즉, 기본값은 프로퍼티로 넘겨주지않아도 사용할 컴포넌트에서 defaultProps를 작성한다면 this.props.defaultValue 등으로 선언만 하면 지정한 기본값으로 사용할 수 있다.
import React, { Component } from "react";
import MyComponent from "./MyComponent";
class App extends Component {
render() {
const obj = { name: "title", page: 30 };
return (
<div>
<MyComponent
objValue={obj}
requiredValue="필수 문자열"
/>
</div>
);
}
}
export default App;
하지만 위에 코드 달리 App 컴포넌트 (상위 컴포넌트)에서 필수 프로퍼티(requiredValue)를 하위 컴포넌트로 넘겨주지 않는다면 필수 프로퍼티로 반드시 전달되어야 하는데 전달되지 않아 필수값이 'undefined'로 지정되지 않았다는는 경고 메시지가 뜬다.
6) 자식 프로퍼티 사용하기
자식 프로퍼티는 자식 컴포넌트 이름의 태그로 감싸서 사용한다. 예를 들어 자식 컴포넌트의 이름이 MyComponent라면 <MyComponent></MyComponent> 의 열고 닫는 태그로 감싸고 그 안에 자식 프로퍼티로 넣을 자식 노드들을 배치하면 된다. 이렇게 넘어온 자식 프로퍼티의 자식 노드들은 children 이라는 방법으로 사용할 수 있다. (만약 children 을 구조분해를 통해서 변수에 넘겨 받는다면 children 그대로 사용하고, 변수에 넘겨 받지 않고 그대로 사용한다면 this.props.children 으로 사용한다. )
import React, { Component } from "react";
import MyComponent from "./MyComponent";
class App extends Component {
render() {
return (
<div>
<MyComponent>
<div><span>자식 노드 1</span></div>
<div><span>자식 노드 2</span></div>
</MyComponent>
</div>
);
}
}
export default App;
App 컴포넌트에서 하위 컴포넌트인 MyComponent에 전달할 값을 MyComponent 태그 사이에 넣어 자식 프로퍼티를 전달한다.
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const { children } = this.props;
return (
<div>
<h2>자식 프로퍼티 전달받기</h2>
{children}
</div>
);
}
}
//자식 프로퍼티 자료형 정의
MyComponent.propTypes = {
children: PropTypes.node,
};
export default MyComponent;
전달받은 자식 프로퍼티는 children 변수에 넣어서 사용한다. 또 children을 const에 구조분해 하지않고 { this.props.children } 으로 사용할 수도 있다. 자식 프로퍼티를 사용하고 그 자식 프로퍼티인 자식 노드의 자료형도 정의하였다. 코드의 결과는 다음과 같다.
위 사진을 보면 알 수 있듯이 children 자리에 자식 프로퍼티로 전달한 " <div><span>자식 노드 1</span></div> " 과
" <div><span>자식 노드 2</span></div> " 가 잘 들어가 있는 것을 볼 수 있다.
6-1) 자식 프로퍼티를 하나만 요구하기
위에 처럼 자식 노드들을 하나만 넣을 수 있지만, 반대로 자식 노드를하나만 요구할 수도 있다. 이는 자식 프로퍼티를 작성할 때 children : PropTypes.element.isRequired 를 작성하면 된다.
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyComponent extends Component {
render() {
const { children } = this.props;
return (
<div>
<h2>자식 프로퍼티 전달받기</h2>
{children}
</div>
);
}
}
//자식 프로퍼티 자료형 정의
MyComponent.propTypes = {
children: PropTypes.element.isRequired, // 자식 프로퍼티 하나만 요구 ⭐
};
export default MyComponent;
위와 같이 자식 프로퍼티로 2개 이상의 자식을 전달한다면 경고 메시지가 뜬다.
쓰다보니 길어졌네요 ㅎㅎ 많은 도움 되셨길 바랍니다 :)
'Javascript > React 지식' 카테고리의 다른 글
[React] 클래스형 컴포넌트 (0) | 2023.04.23 |
---|---|
[React] 컴포넌트의 생명주기로 본 NewCounter 예제 (0) | 2023.04.23 |
[React] 컴포넌트의 생명주기 (2) | 2023.04.23 |
[React] 리액트 컴포넌트 : State (0) | 2023.04.23 |
[React] 리액트의 꽃, 컴포넌트와 그 구성 요소 (0) | 2023.04.21 |