노마드코더 ReactJS로 영화 웹 서비스 만들기 4(props)

딩쓰·2022년 12월 15일
0
post-thumbnail

props에 대해 배워보자!

#4.0 ~ 4.3

4. [2021 UPDATE] PROPS

초기세팅하기

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
  <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
  
    function App() {
      return (
        <div></div>
      );
    }
    
    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);
  </script>
</html>
  • 앞에서 state를 적용한 MinutesToHours랑 KmToMiles을 지워주고 App 컴포넌트만 남김

중복되는 속성(Property)을 재사용 하고 싶다면?

function SaveBtn() {
    return (
      <button style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
      }}>Save Changes</button>
    );
  }
  function ConfirmBtn() {
    return (
      <button style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
      }}>Confirm</button>
    );
  }
  function App() {
    return (
      <div>
        <SaveBtn />
        <ConfirmBtn />
      </div>
    )
  }
  • 위에 처럼style 속성이 똑같은데 두 버튼 다 똑같이 쓰면 코드의 가독성이 떨어지고, 이런 것들이 많아지면 나중에 파일의 크기도 커질 위험이 있음. 또한 오타 등의 오류를 행할 수 있고, 유지보수가 어렵다.
  • 캡슐화와 추상화를 시켜야함!

커스텀한 속성값 가져오는 방법

function Btn(props) {
    console.log(props);
    return (
      <button style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
      }}>
        {props.banana}
      </button>
    );
  }
  function App() {
    return (
      <div>
     //밑의 코드는 Btn({banana="Save Changes", x={false}}) 랑 똑같음
        <Btn banana="Save Changes" x={false} />
        <Btn banana="Continue" y={7} />
      </div>
    )
  }
  • Btn이라는 함수컴포넌트로 캡슐화, 추상화 시켜줌.
  • 버튼의 속성값은 다 똑같고 텍스트만 다르게 하기 위해, 커스텀 속성을 적용해서 banana에 값을 넣어서 그 값을 읽어주는 방식으로 함.
  • 우리가 만들고 사용하는 모든 컴포넌트들은 "()" 괄호로 argument(인자)를 받고, 리액트가 넣어줌.
    => 이 인자 이름은 props임. Btn으로부터 전달 받는 properties 라는뜻
  • props 값을 바로 불러 올 수 있는 간단한 방법임.


💡 props를 console.log() 해보면 하나의 객체로 받는걸 알 수있음.

props 받는 방법을 간단하게 만들기

function Btn({banana}) {
    // console.log(props); //Save Changes //Continue
    return (
      <button style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
      }}>
        {banana} 
      </button>
    );
  }
  • banana는 객체라서 객체를 바로 불러와준다.
  • {banana}이런식으로 적어주면 됨

속성을 여러개, 인자로 가져올 수 있음

function Btn({text, big}) { 
    console.log({text, big});
    return (
      <button style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
      }}>
        {text}
      </button>
    );
  }
  function App() {
    return (
      <div>
        <Btn text="Save Changes" x={false} big={true} />
        <Btn text="Continue" y={7} /> //속성이름은 아무거나 해도됨 
      </div>
    )
  }
  • 파라미터로 커스텀 속성을 다 가져올 수 있음.

폰트도 삼항연산자로 변경 가능

function Btn({banana, big}) {
    console.log(banana, big);
    return (
      <button style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
        fontSize: big ? 18 : 12, //여기
      }}>
        {banana}
      </button>
    );
  }
  function App() {
    return (
      <div>
        <Btn banana="Save Changes" x={false} big={true} />
        <Btn banana="Continue" y={7} big={false} />
      </div>
    )
  }
  • big이라는 속성으로 bigtrue면 18px : false면 12px 이런 식으로도 작성 가능

커스텀 컨포넌트에 이벤트 리스너

function Btn({text, onClick}) {
    return (
      <button 
      onClick={onClick}
      style={{
        backgroundColor: "tomato",
        color: "white",
        padding: "10px 20px",
        border: 0,
        borderRadius: 10,
      }}>
        {text}
      </button>
    );
  }
  function App() {
    const [value, setValue] = React.useState("Save Changes");
    const changeValue = () => setValue('Revert Changes')
    return (
      <div>
        {  // 밑의 onClick은 이벤트 리스너가 아니고 그냥 props임
          // onClick이벤트는 커스텀 컴포넌트에 넣을수 없고 HTML태그 안에 넣야함
        }
        <Btn text={value} onClick={changeValue} />
        <Btn text="Continue" />
      </div>
    )
  }
  • Btn 함수안의 HTML버튼 태그에 들어가 있는 onClick이 진짜 이벤트 리스너이고, 커스텀 컴포넌트에 있는 onClick은 그냥 props이다.
  • props는 text,boolean 뿐만 아니라 위에처럼 function도 보낼 수 있음.

Memo로 리렌더링

  • 위의 콘솔창처럼 첫번째 render는 첫페이지를 열때 실행되고 두번째는 버튼을 눌러서 rerender 됨.
  • <Btn text="Continue" />는 리렌더링 될 필요없는데 같이 리렌더링이 됨.
  • 만약 부모 컴포넌트가 어떤 state라도 변경이 있으면 모든 자식들은 다시 그려질(re-render)거임
    => 이게 추후에 어플리케이션이 느려지는 원인이 될 수도 있음.
<div>
   <Btn text={value} onClick={changeValue} />
   <Btn text="Continue" /> // 리렌더될 필요 없는데 같이 리렌더됨.
</div>

💡React.memo()를 사용해서 props가 변경되지 않는다면 다시 그릴 필요가 없다는 것을 알려줘야함.

function Btn({ text, onClick }) {
    console.log(text, 'was rendered');
    return (
      <button
        onClick={onClick}
        style={{
          backgroundColor: "tomato",
          color: "white",
          padding: "10px 20px",
          border: 0,
          borderRadius: 10,
        }}>
        {text}
      </button>
    );
  }
  const MemorizedBtn = React.memo(Btn);
  function App() {
    const [value, setValue] = React.useState("Save Changes");
    const changeValue = () => setValue('Revert Changes')
    return (
      <div>
        <MemorizedBtn text={value} onClick={changeValue} />
        <MemorizedBtn text="Continue" />
      // 리렌더링 해야할 컴포넌트가 많아지면 이렇게 변화된 것만 리렌더링 되게끔 해줘야 함.
      </div>
    )
  }
  • const MemorizedBtn = React.memo(Btn); 작성하고 커스텀 컴포넌트의 이름을 변경해줌.

  • 이제 continue 버튼은 리렌더링 되지 않음!

Prop Types(props 타입 검증)

만약 협업에서 같이 일하는 사람이 많아질수록, 나만 코드를 작성하는 것이 아니고, 실수를 할 수 있기 때문에 타입 오류를 검사할 수 있는 코드를 작성을 하는 것도 중요함.

prop 타입 오류 예시

function App() {
      return (
        <div>
          <Btn text="Save Changes" fontSize={18} />
          <Btn text={14} fontSize={"Continue"}  />
        </div>
      );
    }
  • 위의 코드는 문법적으로는 괜찮아서 에러는 안나지만, 의미적으로 문제가 있음
    • text에 숫자가 들어가고, fontSize에 string이 들어갔다.

💡 이럴때 리액트에서 PropTypes라는 이름의 패키지로 타입을 검사할 수 있음

타입오류가 생기면 경고문구 띄어주기

propTypes 리액트 문서
CDN 파일참고

  • 아래의 스크립트중 develepment version을 이용
  • 콘솔창에 PropTypes 라고 입력하면 어떤 타입을 검사해줄지 볼 수있음
  • 리액트 스크립트을 아래처럼 development.js버전으로 바꾸고 prop-types 링크도 넣어줌.
 <script src="https://unpkg.com/react@17.0.2/umd/react.development.js "></script>
<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>

PropTypes 작성

function Btn({ text, fontSize = 14 }) {
      return (
        <button
          style={{
            backgroundColor: "tomato",
            color: "white",
            padding: "10px 20px",
            border: 0,
            borderRadius: 10,
            fontSize,
          }}
        >
          {text}
        </button>
      );
    }
    Btn.propTypes = {
      text: PropTypes.string,
      fontSize: PropTypes.number,
    };
    // text는 string, fontSize는 number로 지정해줌

    function App() {
      return (
        <div>
          <Btn text="Save Changes" fontSize={18} />
          <Btn text={14} fontSize={"Continue"}  />
        </div>
      );
    }
  • .propTypes로 text는 string, fontSize는 number로 지정해줌

안지키면 아래처럼 경고가 뜸.

아래처럼 수정하니 오류가 사라짐!

.isRequired 속성

  • 진짜 꼭 있어야 하는 속성은 뒤에 .isRequired를 작성해줌
 Btn.propTypes = {
      text: PropTypes.string.isRequired, //여기
      fontSize: PropTypes.number,
    };

    function App() {
      return (
        <div>
          <Btn text={"Save Changes"} fontSize={18} />
          <Btn fontSize={14} /> 
        </div>
      );
    }
  • 아래 처럼 .isRequired를 작성해 준 속성(여기선 text)이 없으면 경고가 뜸.

폰트 기본 값 정하기 (JS기능)

function Btn({ text, fontSize = 14 }) {
      return (
        <button
          style={{
            backgroundColor: "tomato",
            color: "white",
            padding: "10px 20px",
            border: 0,
            borderRadius: 10,
            fontSize,
          }}
        >
          {text}
        </button>
      );
    }
    Btn.propTypes = {
      text: PropTypes.string.isRequired, //isRequired 속성을 줌
      fontSize: PropTypes.number,
    };

    function App() {
      return (
        <div>
          <Btn text={"Save Changes"} fontSize={18} />
          <Btn text={"Revert Changes"} fontSize={14} /> 
        </div>
      );
    }
  • { text, fontSize = 14 } 이렇게 작성해주면 폰트사이즈 속성에 value가 없을때 자동으로 14px로 적용됨.

    최종코드

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
  <script src="https://unpkg.com/react@17.0.2/umd/react.development.js "></script>
  <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    function Btn({ text, fontSize = 14 }) {
      return (
        <button
          style={{
            backgroundColor: "tomato",
            color: "white",
            padding: "10px 20px",
            border: 0,
            borderRadius: 10,
            fontSize,
          }}
        >
          {text}
        </button>
      );
    }
    Btn.propTypes = {
      text: PropTypes.string.isRequired, //isRequired 속성을 줌
      fontSize: PropTypes.number,
    };

    function App() {
      return (
        <div>
          <Btn text={"Save Changes"} fontSize={18} />
          <Btn text={"Revert Changes"} fontSize={14} /> 
        </div>
      );
    }
    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);
  </script>
</html>
profile
Frontend Developer

0개의 댓글