티스토리 뷰
이 포스팅은 https://nomadcoders.co/react-for-beginners 강의를 보며 작성하였습니다.
#4 Props
Props는 일종의 방식이다. 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 보낼 수 있게 해주는 방법. 이제부터 해볼 것은 부모 컴포넌트로부터 자식 컴포넌트로 데이터를 보내는 것이다.
중요한 점은 컴포넌트는 단지 JXS를 반환하는 함수일 뿐이다.
이러한 작업이 필요한 이유는 무엇일까? 만약 버튼을 만든다고 했을 때 비슷한 스타일의 버튼을 만들기 위해 설정한 style값을 모두 붙여 넣어 만든다면, 추후 수정이 있을 시 모든 버튼의 style값을 조정해야 할 것이다.
function SaveBtn() {
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius:10
}}>Save Changes</button>
}
function ConfirmBtn() {
return <button>Confirm</button>
}
SaveBtn의 style값을 복사해서 ConfirmBtn을 만든다면... 만약 버튼의 개수가 더 늘어난다면??? 너무나 비효율 적일 것이다. 따라서 이러한 방식을 사용하지 않을 것이다.
function Btn() {
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius:10
}}>Save Changes</button>
}
function App() {
return (
<div>
<Btn banana="Save Changes"/>
<Btn banana="Continue"/>
</div>);
}
먼저 Btn이라는 공통적인 button을 만들어 준다. 그리고 App()에서 button두 개를 불러와 랜더링 해준다. 여기서 중요한 점은 Btn은 함수라는 것이다. 따라서 인자를 전달받는 것이 가능하다. 위에서 Btn()에 인자를 받아서 확인해 볼 수 있는데, Btn(props)처럼 인자를 받을 시 props는 우리가 넣은 모든 것을 갖는 오브젝트가 된다. 이 props를 console.log()로 출력하면 다음과 같은 것을 볼 수 있다.
function Btn(props) {
console.log(props);
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius:10
}}>Save Changes</button>
}
우선 Btn에 () 인자를 props로 받은 후 console.log(props)로 출력하면
아래에서 btn에 준 옵션들(banana: "Save Changes")이 나타나는 걸 볼 수 있다. 이 props는 첫 번째 인자이자 유일한 인자이다.(두 번째 인자는 없다!)
function App() {
return (
<div>
<Btn banana="Save Changes" x={false}/>
<Btn banana="Continue" y={5}/>
</div>);
}
여기에 추가로 banana 이외의 x, 와 y의 값을 추가로 준다면
역시 props안에 banana의 값과 x 및 y의 값이 들어 있는 것을 볼 수 있다. 이렇게 banana를 하나의 key값으로 내용을 추적할 수 있고 이것을 이용하여 button에 할당된 text를 banana에 할당되어 있는 문자로 바꾸어 주는 것 또한 가능하다.
function Btn(props) {
console.log(props);
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius:10
}}>Save Changes</button> <-- Save Change를 {props.banana} 로 바꾸어 준다.
}
이렇게 같은 Btn 컴포넌트를 사용하지만, 이 버튼들은 App 컴포넌트에 의해 설정되고 있다.
이러한 props는 숏컷으로도 작성이 가능하다. 직접적으로 인자를 넣지 않고 {}를 이용하여 편하게 받는 것도 가능하다.
<!DOCTYPE html>
<html>
<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.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Btn({banana}) { <--banana 를 적고
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius:10
}}>{banana}</button> <--banana를 받는다
}
function App() {
return (
<div>
<Btn banana="Save Changes"/>
<Btn banana="Continue"/>
</div>);
}
const root = document.getElementById("root");
ReactDOM.render(<App/>, root);
</script>
</html>
이렇게 props자리에 {banana}를 작성해도 똑같이 banana의 값을 가져올 수 있다.
만약 Btn이 두 개의 props값을 가지고 있다면, (banana와 big)
<Btn banana="Save Changes" big="true"/>
<Btn banana="Continue" big="false"/>
Btn({banana, big}) 과 같은 식으로 두 개의 값을 가져올 수 있다. 이것을 이용해 폰트크기를 조정해 보면
<!DOCTYPE html>
<html>
<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.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Btn({banana, big}) { <--banana와 big의 값을 받고
console.log(banana + " "+ big);
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius:10,
fontSize : big ? 25 : 16, <--big이 true라면 폰트는 25 아니라면 16
}}>{banana}</button>
}
function App() {
return (
<div>
<Btn banana="Save Changes" big={true}/>
<Btn banana="Continue" big={false}/>
</div>);
}
const root = document.getElementById("root");
ReactDOM.render(<App/>, root);
</script>
</html>
위와 같은 결괏값을 받을 수 있다.
Props단순한 String값이나 boolean type 이외에도 함수도 보낼 수 있다.
<!DOCTYPE html>
<html>
<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.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Btn({text, changeValue}) {
return <button
onClick={changeValue}
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>
<Btn text={value} changeValue={changeValue}/>
<Btn text="Continue" />
</div>);
}
const root = document.getElementById("root");
ReactDOM.render(<App/>, root);
</script>
</html>
banana를 text로 변경하고 props에 changeValue를 추가해 changeValue라는 함수를 보내준다. Btn(text, changeValue)로 state의 text값과 그 값을 변경할 수 있는 함수를 받을 수 있다. 함수를 onClick event에 등록해 주면 버튼을 클릭 시 changeValue의 setvalue값이 설정되며 "Revert Changes"로 문구가 변화하는 것을 볼 수 있다.
당연한 이야기이지만 단순히 함수를 보낸다고 해서 그 함수가 작동하는 것은 아니다. props로 보낸 함수는 onClick이라는 eventlistener에 등록해 주어야 한다.(line:12 - onClick={changeValue}) 한 가지 더, 과연 이렇게 배정된 함수는 어떻게 render 될까? Btn() 함수에 console.log(text, "was rendered")를 넣어 출력을 해 보면
처음 페이지가 보여질 때 두 개의 버튼이 랜더링 되어 표시된다. 이때 버튼을 누르게 되면 state의 값이 변경되면서 re-render 되어 표시된다.
state가 적용된 버튼은 바뀐 state값인 "Revert Changes"로 문구가 바뀐 것을 볼 수 있다. 또한 Continue버튼은 변경점이 없지만 re-render 되어 표시되었다. 하지만 변경값이 없는 두 번째 버튼은 굳이 re-render 되어야 할 필요가 없다. 리엑트 메모를 이용하여 이러한 점을 해결할 수 있다.
<!DOCTYPE html>
<html>
<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.development.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 MmorizedBtn = React.memo(Btn); <-- 버튼을 리엑트 메모에 연결
function App() {
const [value, setValue] = React.useState("Save Changes");
const changeValue = ()=> {
setValue("Revert Changes");
};
return (
<div>
<MmorizedBtn text={value} changeValue={changeValue}/> <-- memo 버튼 할당
<MmorizedBtn text="Continue" /> <-- memo 버튼 할당
</div>);
}
const root = document.getElementById("root");
ReactDOM.render(<App/>, root);
</script>
</html>
line:22 - const MmorizedBtn = React.memo(Btn); 이렇게 Btn을 memo함수로 변수선언을 해 주고 MmorizedBtn을 기존 버튼에 할당 후 변화를 한번 보면, 처음 페이지가 보일 때는 똑같이 모든 버튼이 렌더링 된다.
하지만 여기서 버튼을 클릭을 하게 되면!
방금 전과는 다르게 Continue 버튼은 랜더링 되지 않고 변경된 Save Changes 버튼만 랜더링 된 것을 볼 수 있다. 이 점은 아주 중요한데 리엑트는 부모의 state값을 자식이 변경시킬 수 있고, 이는 새로운 랜더링을 일으킨다. 하지만, 만약 자식의 수나 컴포넌트의 수가 매우 많다면 앱의 성능저하를 가져올 수도 있다. 따라서 이렇게 props의 값이 '변하지'않는다면 랜더링을 제외시켜 변한 부분만 랜더링이 가능하다.
props는 타입에 대한 정의도 설정할 수 있다. 코드를 다시 되돌려서 Btn에 text값과 number값을 준다.
<!DOCTYPE html>
<html>
<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.development.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}) {
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,
}
function App() {
return (
<div>
<Btn text="Save Changes" fontSize={18}/>
<Btn text={14} fontSize={"18"}/>
</div>
)
}
const root = document.getElementById("root");
ReactDOM.render(<App/>, root);
</script>
</html>
line:4 - <script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script> 스크립트 추가를 해 주고
line:22 - Btn에 대한 props의 타입을 정해줄 수 있다. text 값은 string으로 fontsize는 number로 타입을 지정해 줄 수 있다. 이렇게 타입을 지정하게 되면 잘못된 타입의 값이 들어오면 에러메시지와 함께 실수를 예방할 수 있게 된다.
단순한 타입뿐만 아니라 필수요구사항, 배열, 등등 여러 가지 설정이 가능하다. 자세한 것은 공식 문서 참조.
https://legacy.reactjs.org/docs/typechecking-with-proptypes.html
git : https://github.com/leesulgi66/React_for_Beginners/commit/1f63dd4cce5619d39bdb5990fbf2bb9bb71749c1
'개발일지 > React' 카테고리의 다른 글
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #7 Practice Movie App (0) | 2024.08.20 |
---|---|
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #6 Effects (0) | 2024.08.15 |
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #5 Create React App (0) | 2024.08.13 |
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #3 State (1) | 2024.08.06 |
React를 배워보자(feat. 노마드 코더 - ReactJS 로 영화 웹 서비스 만들기) (0) | 2024.08.03 |