티스토리 뷰

React

Props / Memo / Prop Types

yunieyunie 2023. 5. 2. 12:53

먼저 두 개의 버튼을 만들어 보자.

    function SaveBtn() {
      return <button>Save</button>;
    }

    function ConfirmBtn() {
      return <button>Confirm</button>;
    }

    function App() {
      return (
        <div>
          <SaveBtn />
          <ConfirmBtn />  
        </div>
      )
    }

    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);

 

위와 같은 상황에서 만약 버튼에 같은 style을 추가하고 싶다면 복사 붙여넣기로 각각 추가해줘야 할 것이다.

그런데 각각 style을 추가해주는 대신 같은 설정들을 넘겨줄 수 있는 컴포넌트를 한 개만 만들어 재사용한다면 훨씬 효율적일 것이다.

 

다음과 같이 바꿔보자.

    function Btn({text, big}) {
      return <button style={{
        background: "tomato", color: "white", padding: "10px, 20px", border: 0, borderRadius: 10,  fontSize: big ? 18 : 16 }}>
        {text} </button>;
    }

    function App() {
      return (
        <div>
          <Btn text="Save"  size={true} />
          <Btn text="Confirm" size={false} />
        </div>
      )
    }


    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);

 

1. Props

Props는 부모 컴포넌트에서 자식 컴포넌트에 데이터를 보낼 수 있게 해주는 방법이다.

함수 Btn에 원하는 스타일을 적용시켜 놓고 App에서 Btn을 호출하여 text와 big을 넣는 것이다.

Btn 함수는 다양한 argument를 받으며 argument의 이름은 마음대로 지을 수 있다.

이러한 다양한 argument를 property 또는 props라고 부른다.

즉, 컴포넌트에 보내지는 argument인 것이다.

리액트가 하는 작업은 Btn함수를 호출하여 props들을 첫 번째 인자로 넣는 것이다.

 

그런데 App 안에서 불러온 Btn에 prop을 추가하는 것은 이벤트 리스너가 아니며 그냥 Btn 함수에 들어가는 prop일 뿐이다.

이벤트 리스너는 Btn 함수 자체에 넣어줘야 한다.

 

    function Btn({text, onClick}) {
      return <button onClick={onClick} style={{
        background: "tomato", color: "white", padding: "10px 20px", border: 0, borderRadius: 10}}>
        {text} </button>;
    }

    function App() {
      const [value, setValue] = React.useState("Save");
      const changeValue = () => setValue("revert changes");
      return (
        <div>
          <Btn text={value} onClick={changeValue} />
          <Btn text="Confirm"/>
        </div>
      )
    }

    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);

 

위와 같이 App 안 Btn에서의 onClick은 그냥 prop의 이름일 뿐이며 이를 Btn 함수가 인자로 받아 onclick 이벤트 리스너로 실행시켜주는 것이다.

만약 Btn 함수 안에서 onclick 이벤트 리스너가 없고 App 안 Btn에만 onclick이 있다면 이는 적용되지 않을 것이다. 

그저 prop이기 때문이다.

 

 

2. Memo

그런데 버튼을 클릭하면 value가 바뀌고 re-render가 되는데 변화가 없었던 confirm 버튼도 같이 re-render가 된다.

부모 컴포넌트의 state를 변경하면 당연히 그 자식 컴포넌트도 re-render가 일어나기 때문이다.

그런데 이는 어플리케이션이 느려지는 원인이 될 수 있다.

prop가 변경되지 않아서 불필요한 re-render가 없길 원하는 컴포넌트가 있다면 React Memo를 사용해보자.

 

https://ko.reactjs.org/docs/react-api.html#reactmemo

 

React 최상위 API – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

React.memo는 고차 컴포넌트(Higher Order Component)입니다.
컴포넌트가 동일한 props로 동일한 결과를 렌더링해낸다면, React.memo를 호출하고 결과를 메모이징(Memoizing)하도록 래핑하여 경우에 따라 성능 향상을 누릴 수 있습니다. 즉, React는 컴포넌트를 렌더링하지 않고 마지막으로 렌더링된 결과를 재사용합니다.

    function Btn({text, onClick}) {
      return <button onClick={onClick} style={{
        background: "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="confirm"/>
        </div>
      )
    }


    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);

 

위와 같은 코드에서는 save changes 버튼을 눌러도 옆에 있는 confirm 버튼은 re-render가 되지 않는다.

prop가 변경되지 않는다면, 즉 state가 변경되지 않았다면 re-render하지 않도록 하여 불필요한 re-render가 일어나는 것을 막을 수 있다.

 

 

3. Prop Types

만약 각 props에 특정 타입이 입력되길 원하다면 proptype을 설치하여 사용해보자.

function Btn({text, fontSize}) {
      return <button style={{
        background: "tomato", color: "white", padding: "10px 20px", border: 0, borderRadius: 10, fontSize}}>
        {text} </button>;
    }

    Btn.propTypes = {
      text: PropTypes.string, fontSize: PropTypes.number
    };

    function App() {
      return (
        <div>
          <Btn text="save" fontSize={18} />
          <Btn text="confirm" fontSize={12} />
        </div>
      )
    }


    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);

위의 코드는 text에는 string, fontSize에는 number가 들어와야 함을 정해주는 것이다.

다른 타입이 들어가면 에러는 안나지만 콘솔창에서 경고가 뜨는 것을 확인할 수 있다.

 

만약 뒤에 .isRequired를 붙인다면 해당 prop는 반드시 가지고 있어야 함을 의미하며 해당 prop이 빠져있다면 경고창이 뜨는 것을 확인할 수 있다. 

Btn.propTypes = {
      text: PropTypes.string.isRequired, fontSize: PropTypes.number.isRequired
    };

 

prop의 기본값을 설정할 수도 있다.

다음과 같이 두번째 버튼에는 fontSize prop이 없으므로 Btn에서 정의한 fontSize인 16이 적용된다.

function Btn({text, fontSize = 16}) {
      return <button style={{
        background: "tomato", color: "white", padding: "10px 20px", border: 0, borderRadius: 10, fontSize}}>
        {text} </button>;
    }

    Btn.propTypes = {
      text: PropTypes.string.isRequired, fontSize: PropTypes.number
    };

    function App() {
      return (
        <div>
          <Btn text="save" fontSize={18} />
          <Btn text="confirm" />
        </div>
      )
    }


    const root = document.getElementById("root");
    ReactDOM.render(<App />, root);

 

 

 

 

'React' 카테고리의 다른 글

🔎 Create React App  (0) 2023.05.02
React로 단위 변환기 만들기 💻  (0) 2023.05.01
Vanilla JS 🆚 React JS  (0) 2023.04.24
댓글