마크업이나 스타일을 최대한 재사용할 수 있도록 아래 두가지 버튼을 예로 props를 사용해보자.
props는 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 보낼 수 있게 해주는 방법으로 어떠한 값을 컴포넌트에 전달 해줘야할 때 props를 사용한다.
아래 코드는 같은 스타일을 가진 버튼 두개를 만드는 코드이다.
style을 복붙하는 것 대신에 설정들을 넘겨줄 수 있는 버튼 컴포넌트를 만들어서 데이터를 전송해준 것이다.
function Btn({text}) {
return (
<button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius: 10
}}>
{text}
</button>
)
}
function App() {
return (
<div>
<Btn text="Save Changes" />
<Btn text="Continue" />
</div>
)
}
const root = document.getElementById("root")
ReactDOM.render(<App />, root)
참고?
<img src=" "태그의 src="" 부분은 img태그에 정보를 전송하는데,
비슷한 방법으로 동일한 syntax를 사용하면서 새로운 데이터(정보)를 Btn 컴포넌트에 전송해준다.
참고2?
prop을 사용하는 다른 방식
function Btn(props) {
...
{props.text}
}
이렇게 사용할 수 있지만 위의 예제 코드처럼 property를 오브젝트로부터 꺼내는 방식을 선호한다고 한다.
props는 오브젝트이기 때문에 우리가 App 컴포넌트의 Btn에서 보낸 모든 것들을 가질 수 있다.
따라서 인자를 하나만 가질 수 있는게 아니라 여러 데이터를 전달받아 사용할 수 있다.
function Btn({text, big}) {
return (
<button style={{
...
fontSize: big ? 18 : 16
}}>
{text}
</button>
)
}
function App() {
return (
<div>
<Btn text="Save Changes" big={true}/>
<Btn text="Continue" big={false}/>
</div>
)
}
우선 React memo의 필요성에 대해 알아보기 위해 state를 활용하여 컴포넌트 상태가 바뀌는 예시를 들어보자
function Btn({text, onClick}) {
console.log(text, "was rendered"
return (
<button
onClick = {onClick}
...
}}>
{text}
</button>
)
}
function App() {
const [value, setValue] = React.useState("Save Changes")
const changeValue = () => setValue("Revert Changes")
return (
<div>
<Btn text={value} onClick={changeValue} />
<Btn text="Continue" />
</div>
)
}
중요!!
여기서 전달하는 onClick은 실제 이벤트리스너가 아니라 Btn 컴포넌트로 전달하는 prop이다. text 처럼 그냥 이름이기 때문에 Btn 컴포넌트에서 이름을 가져와서 적용시켜주어야 함에 유의하자.
-처음 페이지 렌더했을때 로그
-Save Changes 버튼 클릭했을때 로그
컴포넌트는 상태가 바뀌면 re-render를 하는데 이로 인해서 Save Changes 버튼을 눌럿을때 해당 버튼만 렌더되는 것이 아닌 Continue 버튼도 다시 렌더되는 것을 볼 수 있다.
그러나 변경된 사항이 없는 Continue 버튼의 경우 렌더를 다시할 필요가 없기때문에 React memo를 이용하여 개선할 수 있다.
React memo는 컴포넌트가 다시 그려지는 것을 윈치않을 경우에 props가 변경되지 않는 한에서 사용할 수 있다.
state가 변경되면 Changes 버튼도 변경되어야하는데 Continue 버튼의 경우 onClick props가 아니기때문에 re-render를 방지하기 위해 React에 해당 버튼의 re-render를 멈춰달라고 말할 수 있다.
function Btn({text, onClick}) {
...
}
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)
function Btn() 으로 컴포넌트를 생성해주고,
MemorizeBtn은 memorized 버전의 Btn이 된다.
<MemorizedBtn text={value} onClick={changeValue} />
<MemorizedBtn text="Continue" />
App 컴포넌트의 Btn -> MemorizedBtn로 교체하여 Continue 버튼의 re-render를 방지할 수 있다.
-처음 페이지 렌더했을때 로그
-Save Changes 버튼 클릭했을때 로그
부모의 state가 변경되면 모든 자식은 re-render되기 때문에 어플리케이션이 느려지는 원인이 될 수 있다. 따라서 memo를 적절히 사용하면 이를 방지할 수 있는 좋은 방법이 된다.
유저가 prop으로 데이터를 전달할때 Syntax error가 아닌 실수가 발생 할 수 있다.
예를 들어
<Btn text="Save Changes" fontSize={18} />
<Btn text="{14}" fontSize="Continue" />
두번째 버튼에서 우리는 text -> string, fontSize -> number 타입이 나오길 바라지만 React.js는 구분할 줄 모른다.
props type은 이럴 경우에 사용하여 prop들이 무슨 type인지 알려줄 수 있다.
<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>
...
Btn.propType = {
text: PropTypes.string.isRequired
fontSize: PropTypes.number
}
위처럼 propType을 사용하면 props의 타입이 어떤것이고 어떤 모양이어야하는지 정의할 수 있기 때문에 벗어날 경우 콘솔창에서 경고로그를 확인 할 수 있다.