๐ŸŒˆ PropTypes

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋˜๋Š” Prop(์†์„ฑ)์˜ Type(ํƒ€์ž…)์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
EmotionCard.propTypes = {
// ์ „๋‹ฌ ์†์„ฑ ๊ฐ์ฒด, ์†์„ฑ ์ด๋ฆ„, ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„
emotion(props, propName, componentName) {
// ์ฒดํฌํ•  ์œ ํ˜•
const checkType = "string";
// ์ „๋‹ฌ ์†์„ฑ ์œ ํ˜•
const propType = typeof props[propName];

// ์ „๋‹ฌ ์†์„ฑ ๊ฒ€์‚ฌ (๋ฌธ์ž ๊ฐ’์ธ์ง€ ํ™•์ธ)
if (propType !== checkType) {
// ๋ฌธ์ž ๊ฐ’์ด ์•„๋‹Œ ๊ฒฝ์šฐ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
throw new Error(
`${componentName} ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ ๋œ ์†์„ฑ ${propName}์˜ ๋ฐ์ดํ„ฐ ์œ ํ˜•์€ ${checkType}์ด ์š”๊ตฌ๋˜๋‚˜, ์‹ค์ œ ์ „๋‹ฌ๋œ ์†์„ฑ ์œ ํ˜•์€ ${propType}์ด๋‹ˆ ํ™•์ธ ๋ฐ”๋ž๋‹ˆ๋‹ค.`
);
}
},
};

์œ„์™€ ๊ฐ™์ด ์ง์ ‘ custom propTypes๋ฅผ ํ†ตํ•ด prop๋ฅผ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฆฌ์•กํŠธ ํŒ€์—์„œ ์ œ๊ณตํ•˜๋Š” propTypes ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŽธ๋ฆฌํ•˜๊ณ  ์•ˆ์ •์ ์œผ๋กœ prop ๊ฒ€์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŒจํ‚ค์ง€ ์‚ฌ์šฉ

์„ค์น˜

1
npm i -D prop-types

์‚ฌ์šฉ ์˜ˆ์‹œ

1
2
3
4
5
6
7
8
9
10
import PropTypes from "prop-types";

// ...

Worker.propTypes = {
name: PropTypes.string.isRequired,
career: PropTypes.number,
onCareerUp: PropTypes.func,
isLeave: PropTypes.bool,
};
  • isRequired ๋Š” ํ•„์ˆ˜์ž…๋ ฅ์„ ์š”๊ตฌํ•˜๋Š” ์†์„ฑ์„ ํ‘œ์‹œํ•œ๋‹ค.

propTypes ๊ฒ€์‚ฌ ํ•ญ๋ชฉ

propType_categories

PropTypes๏น•objectOf vs. shape

1
2
3
4
5
6
7
8
9
10
import { objectOf, number } from "prop-types";

const geoProps = {
latitude: 37.331706,
longitude: -122.030783,
};

ReactComponent.propTypes = {
geoProps: objectOf(number),
};
  • propTypes.objectOf ๋Š” ๊ฐ์ฒด์˜ ์†์„ฑ ๊ฐ’์ด ๋ชจ๋‘ ๋™์ผํ•œ ํƒ€์ž…์„ ์„ค๋ช…ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
import { shape, arrayOf, string } from "prop-types";

const personProp = {
name: "์•ผ๋ฌด",
job: ["๊ฐ•์‚ฌ", "๋””์ž์ด๋„ˆ", "๊ฐœ๋ฐœ์ž"],
};

ReactComponent.propTypes = {
personProp: shape({
name: string,
job: arrayOf(string),
}),
};
  • ๋‚ด๊ฐ€ ๊ฐ์ฒด prop ํƒ€์ž… ์„ค์ •ํ•˜๊ณ  ์‹ถ๋‹คํ•˜๋ฉด shape๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • propTypes.shape ๋Š” ๊ฐ์ฒด์˜ ๊ฐ ์†์„ฑ๋ณ„ ํƒ€์ž…์„ ์„ค๋ช…ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๊ฐ์ฒด์˜ name ์†์„ฑ์€ string, job ์†์„ฑ์€ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.
  • job์˜ ๋ฐฐ์—ด์—๋Š” string์œผ๋กœ๋งŒ ๊ตฌ์„ฑ๋œ ๋ฐฐ์—ด์ด๋ฏ€๋กœ arrayOf๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๊ฐ์ฒด์˜ ์†์„ฑ์ด ์ •ํ™•ํžˆ ๋™์ผํ•˜๊ฒŒ ์ผ์น˜ํ•ด์•ผํ•œ๋‹ค๋ฉด propTypes.exact()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

โ—๏ธ Null ํƒ€์ž… ์ฒดํฌ ์ฃผ์˜

propTypes๋Š” null ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ•  ์ˆ˜ ์—†์–ด oneOf๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
import { oneOf, oneOfType, shape, string } from "prop-types";

SignInedInfo.propTypes = {
authUser: oneOfType([
oneOf([null]), // โ† ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
shape({
displayName: string.isRequired,
photoURL: string.isRequired,
}),
]).isRequired,
};
  • PropTypes.oneOf([โ€™growโ€™, โ€˜learnโ€™, โ€˜connectโ€™]) ์ด ์ค‘ ํ•˜๋‚˜๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ”ฅ defaultProps์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ธฐ

ํ•จ์ˆ˜์— ๊ธฐ๋ณธ๊ฐ’์„ ์ฃผ๋“ฏ์ด props์— ๊ธฐ๋ณธ๊ฐ’์„ ์ฃผ๋Š” ๊ฒƒ์„ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ง€์–‘ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ธฐ๋ณธ๊ฐ’์„ ์ค˜์•ผํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from 'react';
import { number, bool}

const Worker = ({ name, career, onCareerUp, isLeave }) => (
// ...
);

// Worker ์ปดํฌ๋„ŒํŠธ ์ „๋‹ฌ ์†์„ฑ ๊ธฐ๋ณธ ๊ฐ’ ์„ค์ •
Worker.defaultProps = {
career: 0,
isLeave: true,
}

Worker.propTypes = {
career:number,
isLeave: bool
}

export { Worker };
  • boolean ๋Œ€์‹  bool์ด๋ผ๊ณ  ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.