그럼에도 불구하고

👨‍💻

[React with TS] PropTypes란? 본문

React/React basics

[React with TS] PropTypes란?

zenghyun 2023. 6. 28. 20:09

PropTypes를 이용하여 리액트 컴포넌트의 유효성을 검증하는 방법에 대해 알아보겠습니다.

 

 

목차

     

    [ 속성의 유효성 검증 방법 ]

    리액트 컴포넌트의 유효성을 검증하는 방법은 여러 가지가 있습니다만 타입스크립트를 사용한다면 타입스크립트의 정적 타입 지원 기능을 이용할 수 있습니다. 이 방법은 컴파일(빌드) 시에 타입을 검사하며, IDE를 통해서 코드 자동완성 기능을 지원받을 수 있습니다.

     

    또 다른 유효성 검증 기능으로는 PropTypes가 있습니다. PropTypes는 리액트가 지원하는 기능이며, 컴파일할 때가 아닌 실행 중에 속성에 대한 유효성 검증을 수행합니다.  따라서 속성으로 전달하는 값과 타입에 따라 경고를 발생시킵니다. 

     

    일반적으로는 타입스크립트의 정적 타입을 이용한 유효성 검증만으로도 충분하지만, 좀 더 엄격한 속성 유효성 검증 기능이 필요하다면 위에서 설명한 두 가지를 병행하여 적용할 수 있습니다. 

     

    [ PropTypes를 이용한 유효성 검증 ]

    타입스크립트로 정적 타입의 속성을 전달하는 Calc 컴포넌트를 작성해보겠습니다.

     

    📌 Calc.tsx

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    import React from "react";
     
    type CalcPropsTypes = {
      x: number;
      y: number;
      oper: string;
    };
     
    const Calc = (props: CalcPropsTypes) => {
      let result: number;
     
      switch (props.oper) {
        case "+":
          result = props.x + props.y;
          break;
        case "*":
          result = props.x + props.y;
          break;
        default:
          result = 0;
      }
      return (
        <div>
          <h3>연산 방식 : {props.oper}</h3>
          <hr />
          <div>
            {props.x} {props.oper} {props.y} = {result}
          </div>
        </div>
      );
    };
     
     
     
    export default Calc;
     
    cs

     

     

    📌 App.tsx

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import React, { useState } from "react";
    import Calc from "./Calc";
     
    function App() {
      const [x, setX] = useState<number>(80);
      const [y, setY] = useState<number>(50);
      const [oper, setOper] = useState<string>("+");
     
      return (
        <>
        <Calc x={x} y={y} oper={oper}/>
        </>
      );
    }
     
    export default App;
     
    cs

     

    다음과 같이 작성 후 개발 서버를 구동하고 브라우저 화면으로 확인하면 문제없이 잘 실행됩니다. 하지만 oper 상태를 "+" 대신에 "&"로 변경하면 아무런 에러 메시지 없이 결괏값이 0으로 나타나게 됩니다.

     

    결과가 0으로 나오는 이유는 Calc 컴포넌트에서 oper가 + 또는 *이 아니라면 0으로 결과를 리턴하도록 default 값을 지정했기 때문입니다. 그러나 이보다는 실행 중에 속성으로 전달된 값을 확인하여 에러 메시지타 경고 메시지를 알려주는 것이 바람직합니다.

     

    이제 이 예제에 PropTypes를 적용해 보겠습니다.  

     

    // npm 이용시
    npm install prop-types 
    
    // yarn 이용시 
    yarn add prop-types

     

    📌 Calc.tsx

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    import React from "react";
    import PropTypes from 'prop-types';
     
    type CalcPropsTypes = {
      x: number;
      y: number;
      oper: string;
    };
     
    const Calc = (props: CalcPropsTypes) => {
      let result: number;
     
      switch (props.oper) {
        case "+":
          result = props.x + props.y;
          break;
        case "*":
          result = props.x + props.y;
          break;
        default:
          result = 0;
      }
      return (
        <div>
          <h3>연산 방식 : {props.oper}</h3>
          <hr />
          <div>
            {props.x} {props.oper} {props.y} = {result}
          </div>
        </div>
      );
    };
     
    /*
     props: 컴포넌트로 전달된 속성 
     propName: x, y, oper와 같은 속성의 이름
     componentName: 컴포넌트의 이름 
     */
     
     
    const calcChecker = (props:any, propName: string, componentName: string) => {
        if(propName === "oper") {
            if(props[propName] !== "+" && props[propName] !== "*") {
                return new Error(`${propName} 속성의 값은 반드시 '+''*'만 허용합니다. (at ${componentName}).`);
            }
        }
    };
     
    Calc.propTypes = {
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
        oper: calcChecker,
    };
     
     
     
    export default Calc;
     
    cs

     

    propTypes 멤버에 속성에 대한 유효성 검증 정보를 작성합니다. x, y 속성은 숫자(number)만 전달할 수 있으며, 속성을 필수로 (isRequired) 전달해야 합니다. PropTypes는 여러 가지 타입에 대한 기본적인 설정을 할 수 있도록 number, string, boolean과 같은 타입 정보를 제공합니다.

     

    calcChecker 함수는 oper 속성의 값이 +와 *중에 하나가 아니라면 Error 객체를 리턴에 경고를 발생시킵니다.  

     

    여기서 의도적으로 잘못된 속성 값을 전달하도록 App 컴포넌트의 코드를 변경해 보겠습니다. 

     

    y 상태의 값을 문자열 타입으로, oper 상태를 &로 변경합니다. 

     

     

    📌 App.tsx

      const [x, setX] = useState<number>(80);
      const [y, setY] = useState<number>("50");
      const [oper, setOper] = useState<string>("&");

     

    타입스크립트의 정적 타입 체크 기능을 이용해 컴파일하면 아래와 같이 브라우저의 개발자 도구에서 에러 메시지가 나타납니다. 

     

    [ 지정 가능한 유효성 검증 타입 ]

    이번에는 PropTypes를 이용해 유효성을 검증할 때 사용할 수 있는 타입을 살펴보겠습니다. 단순 타입은 다음과 같습니다.

     

    • PropTypes.array : 배열 타입
    • PropTypes.bool : true/false의 불리언 타입 
    • PropTypes.func : 속성을 이용해 함수와 메서드를 전달하는 함수 타입 
    • PropTypes.number : 숫자 타입
    • PropTypes.object : 객체 타입
    • PropTypes.string: 문자열 타입 

    이런 단순 타입으로 실행할 수 있는 유효성 검증은 타입스크립트의 정적 타입 속성만으로도 충분히 할 수 있습니다. 좀 더 복잡한 유효성 검증 타입은 다음과 같습니다.

     

    • PropTypes.instanceOf(Customer) : Customer 클래스의 인스턴스인지를 검증
    • PropTypes.oneOf(['+', '*']) : []에 포함된 값 중의 하나인지를 검증
    • PropTypes.oneOfType([PropTypes.number, PropTypes.string]) : []에 포함된 타입의 값인지를 검증 
    • PropTypes.arrayOf(PropTypes.object) : 객체의 배열인지를 검증 

    이처럼 복잡한 객체와 배열 속성을 검증하기 위한 검증 타입도 필요하지만, 반드시 알아두어야 할 기능은 바로 이미 작성한 적이 있는 함수를 이용한 사용자 정의 유효성 검증 기능입니다.

     

    const calcChecker = (props:any, propName: string, componentName: string) => {
        if(propName === "oper") {
            if(props[propName] !== "+" && props[propName] !== "*") {
                return new Error(`${propName} 속성의 값은 반드시 '+', '*'만 허용합니다. (at ${componentName}).`);
            }
        } 
        
    Calc.propTypes = {
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
        // y: calcChecker,
        oper: calcChecker,
    };

     

    • props : 컴포넌트로 전달된 속성
    • propName : x, y, oper와 같은 속성의 이름
    • componentName : 컴포넌트의 이름이며, 유효성 검증을 위한 함수를 여러 컴포넌트에서 사용할 경우, 컴포넌트 이름으로 컴포넌트를 식별합니다. 

     

    기존 Calc.tsx에 'y 속성은 0에서 100 사이의 짝수여야 한다.'는 새로운 유효성 검증 요구 사항을 추가해 보겠습니다.

     

     

    📌 Calc.tsx

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    import React from "react";
    import PropTypes from 'prop-types';
     
    type CalcPropsTypes = {
      x: number;
      y: number;
      oper: string;
    };
     
    const Calc = (props: CalcPropsTypes) => {
      let result: number;
     
      switch (props.oper) {
        case "+":
          result = props.x + props.y;
          break;
        case "*":
          result = props.x + props.y;
          break;
        default:
          result = 0;
      }
      return (
        <div>
          <h3>연산 방식 : {props.oper}</h3>
          <hr />
          <div>
            {props.x} {props.oper} {props.y} = {result}
          </div>
        </div>
      );
    };
     
    /*
     props: 컴포넌트로 전달된 속성 
     propName: x, y, oper와 같은 속성의 이름
     componentName: 컴포넌트의 이름 
     */
     
     
    const calcChecker = (props:any, propName: string, componentName: string) => {
        if(propName === "oper") {
            if(props[propName] !== "+" && props[propName] !== "*") {
                return new Error(`${propName} 속성의 값은 반드시 '+''*'만 허용합니다. (at ${componentName}).`);
            }
        } 
     
        if(propName === "y") {
            const y = props[propName]; 
            if( y > 100 || y < 0 || y % 2 !== 0) {
                return new Error(`${propName}속성의 값은 0 이상 100 이하의 짝수만 허용합니다. (at ${componentName}).`);
            }
        }
    };
     
    Calc.propTypes = {
        x: PropTypes.number.isRequired,
        y: calcChecker,
        oper: calcChecker,
    };
     
     
     
    export default Calc;
     
    cs

     

    이제 y의 값에 0 이상 100 이하의 짝수가 아니면 다음과 같은 오류가 발생하게 됩니다.

     

    [ 속성의 기본값 지정 ]

     

    속성의 기본 값은 아래와 같이 지정할 수 있습니다. 

     

    Calc.defaultProps = {
        x: 100,
        y: 20,
        oper: '+'
    };

     

     

    Comments