본문 바로가기
Web Service/React

[영화 웹 서비스 만들기] #6. Props

by junnykim 2022. 3. 22.

~4.3까지의 강의~

 

앞선 강의에서, 우리는 logic을 가지고 말 그대로 JSX를 분리된 component로 만들었다. (<MilestoKim /> 이런거)

props는 부모 component로부터 자식 component에 데이터를 보낼 수 있게 해주는 방법이다. 앞서서,  자식 component는 부모 component의 데이터를 필요로 하지 않고, 독립적이 었다. (자식 component는 <MiletoKim />이런거 였고, 부모는 <App/>이었음)

이제, 부모 component로부터 자식 component로 데이터를 보내보자. 그 전에 props로 해결이 가능하게 될 문제들을 가정해보자. 어플리케이션은 다양한 버튼을 가지고 있는데, 어떻게 리액트 component를 재사용 할 수 있을까?!

component는 단지 JSX를 반환하는 함수이다. 그게 component이다.

 

먼저, 스타일을 넣어주자. 스타일을 바꾸는 방법에는 여러가지가 있지만, 기본적으로 버튼의 style 요소를 사용해 스타일을 변경해보자.

<button                   
  style={{                       
   backgroundColor: "tomato",                       
   color: "white",                       
   padding:"10px 20px",                       
   border:0,                       
   borderRadius:10,                     
>

 

그런데, 버튼을 2개 사용하는 과정에서, 스타일을 재사용하고 싶어졌다.

how?? ->img 태그에 지정하는거랑 비슷한 방법으로 사용한다.

 

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" /> 
                   <Btn banana="Confirm" /> 
                </div>
            );
        }
이름은 아무거나로 지정해도 된다. 우리가 사용하는 모든 component들은 괄호로 인자를 받는다. 이건 리액트가 넣어준다. 첫번째는 마음대로 이름을 지어줄 수 있는데, 사람들은 이걸 props라고 부른다.
 
아래 두 개는 같은 말이다.
<Btn banana="Save Changes" />
Btn({banana:"Save Changes"}) 
 
우리가 넣어준 모든 것들을 첫 번째 인자로써 넣어준다. 리액트는 자동으로 우리가 넣는 모든 props들을 모조리 오브젝트 안으로 집어 넣는다. 오브젝트는 component의 첫 번째 인자로 주어진다.

 

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

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

 

 

그런데, props의 이름을 변경한다면 동시에 component의 이름도 바꾸어야 한다.  반영된게 위의 코드

 

전체 코드

더보기
<!DOCTYPE html>
<html>
    <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 Btn({text,big}){
            //console.log(text, big);
            return (
                <button
                    style={{
                        backgroundColor: "tomato",
                        color: "white",
                        padding:"10px 20px",
                        border:0,
                        borderRadius:10,
                        fontSize: big ? 18 : 16,
                    }}
                >
                    {text}
                </button>
            );
        }

        function App(){
            return(
                <div>
                   <Btn text="Save Changes" big={true} /> 
                   <Btn text="Confirm" big={false}/> 
                </div>
            );
        }
        const root = document.getElementById("root");
        ReactDOM.render(<App/ >, root);
    </script>
</html>

 

최종. 크기 다른건 이제 말 안하겠음

 

결론 : 자식이 부모에 prop으로 값 전달한다. 이름은 동일 해야 한다. prop을 사용하면 최대한 재사용할 수 있다.


props에 뭘 또 넣을 수 있는지 보자. 그리고 버튼을 rendering하는 component도 알아보자.

 

<Btn text={value} onClick={changeValue} />

위의 코드에서, onClick은 이벤트 리스너가 아니라, prop이다. 이름이 같을지도 모르겠지만, 리액트가 이벤트 리스너를 추가시키는 게 아니다. prop의 이름이다! 만약에 버튼을 클릭하면, 어디에도 onClick은 없는 것이다. 이것은 버튼으로 들어가는 무엇인가가 아니라, Btn component로 들어가는 무엇인가 이다. 그러나 prop으로 뭐든 넣으면 자동적으로 return 되는 것이 아니라 항상 우리가 써줘야 한다! (최종 코드에서는 이름 변경함)

 

changeValue의 결과로 Revert!

 
 
React memo
const MemorizedBtn = React.memo(Btn);

//일반
return(               
<div>                   
  <Btn text={value} changeValue={changeValue} />                     
  <Btn text="bye" />                
</div>           
);         

//React Memo           
return(               
<div>                   
  <MemorizedBtn text={value} changeValue={changeValue} />                     
  <MemorizedBtn text="bye" />                
</div>           
);
onClick 함수가 call할 때 위의 코드 값들이 재설정 될 것이고, re-render를 볼 것이다. 왜냐하면, 데이터를 수정하는 함수가 불려질 때 다시 re-render될 것이기 때문이다.
부모 component는 state 변경을 겪고, 그 state가 변경될 때 모든 게 새로 그려진다(re-render). 부모의 state를 바꾸는 함수를 만들었고, 함수를 실행하는 데 그건 자식이 실행시킨다. 리액트 규칙에 의해서 component가 state를 바꾼다면 re-render해야 한다. 근데 re-render를 원치 않는 다고 알려줄 때, 우리는 React memo라고 불리는 걸 할수 있다. 이 때 memo는 Memorize이다.
 

전체코드

더보기
<!DOCTYPE html>
<html>
    <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 Btn({ text, changeValue }){
            console.log(text, "was rendered");
            return (
                <button
                    onClick={changeValue}
                    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>
                   <Btn text={value} changeValue={changeValue} />  
                   <Btn text="bye" /> 
                </div>
            );*/
            //React Memo
            return(
                <div>
                   <MemorizedBtn text={value} changeValue={changeValue} />  
                   <MemorizedBtn text="bye" /> 
                </div>
            );
        }
        const root = document.getElementById("root");
        ReactDOM.render(<App/ >, root);
    </script>
</html>

 

React memo의 결과!

 


component가 아주 많을 때 실수가 생길 수도 있다. 이 때 proptype은 어떤 타입의 prop을 받고 있는지 체크해준다.

 

<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>

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

 

전체 코드

더보기
<!DOCTYPE html>
<html>
    <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 src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script> 
    <script type="text/babel">  
        function Btn({text, fontSize = 14}){
            console.log(text, "was rendered");
            return (
                <button
                    onClick={changeValue}
                    style={{
                        backgroundColor: "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 Changes" fontSize={18} />
                   <Btn text="Confirm" />
                </div>
            );
        }
        const root = document.getElementById("root");
        ReactDOM.render(<App/ >, root);
    </script>
</html>

 

 


 

 

결론: 설정 가능한 component를 갖는다는건 훌륭하다. 최대한 재사용할 수 있다. 우리는 복붙하는 대신 Btn component를 만든 것이다. prop들은 단지 인자를 사용해 component에 데이터를 보내기 위한 것이다.

prop에 접근하는 것은 첫 번쨰 인자 안에서 가능하다. 첫번째 인자에서 prop들을 하나의 오브젝트로서 받는 것이다. 접근하고 싶으면 component 이름은 전달할때와 받아서할 때랑 이름이 동일해야 한다.

우리는 재사용할 수 있게끔 component 사용하는 방법을 배웠다. 

댓글