[React] Props

오리·2024년 4월 13일
post-thumbnail

1. Props란?

  • 컴포넌트 속성을 설정할 때 사용하는 요소이다.
  • 상위 컴포넌트에서 하위 컴포넌트로 전달한다. (단방향 흐름)

2. 함수형 컴포넌트 props

function App() {
	<FunProps weather="sunny" feeling="happy" />
}

-> 이런식으로 부모요소에서 props를 전달할 수 있는데, 자식요소에서 어떻게 props의 값을 뽑아낼 수 있는지 알아보자!

1) props 매개변수(인자)의 점접근법

export default funtion Funprops(props) {
    console.log(props);
    // {weather: 'sunny', feeling: 'happy'}의 객체형태로 저장됨
return (
      <>
          <div>weather props로 전달받은 데이터: {props.weather}</div>
          <div>feeling props로 전달받은 데이터: {props.feeling}</div>
      </>
	);
} 

2) 컴포넌트 내에서 props 매개변수를 구조분해

  • 바로 값을 사용할 수 있도록 구조분해 할당 한다.
  • 구조분해할당 할때, key의 이름과 같아야 한다.
    -> 예를들어, 부모에서 props이름을 weather로 했으면 자식이 받을때도 이름이 weather여야 undefined가 뜨지 않는다.
export default function FunProps(props) {
	const { weather, feeling } = props;
    
 	return (
    	<div>{weather}</div>
        <div>{feeling}</div>
    );
}

3) 매개변수로 받아올때부터 구조분해

export default function FunProps({ weather, feeling }) {
	return (
    <div>{weather}</div>
    <div>{feeling}</div>
    );
}

4) default Props

  • 부모 컴포넌트에서 props가 전달되지 않았을때 기본값으로 보여줄 props를 설정한다.

  • 부모 컴포넌트
    -> 아무것도 전달되지 않았다. 이럴때 default값을 설정해야 한다.

<FunProps />
export default function FunProps ({ weather, feeling, date }) {
	return (
    	<>
        	<div>weather props로 전달받은 데이터 : {weather}</div>
            <div>feeling props로 전달받은 데이터 : {feeling}</div>
            <div>오늘의 날짜는 {date} 입니다. </div>
        </>
    );
}

FunProps.defaultProps = {
	weather : "cloudy", 
};

5) propTypes

  • props의 타입을 지정할 때 사용한다.

  • 자바스크립트의 "유연한 특성"을 해결하기 위해 사용한다.

  • props의 타입을 지정해 예기치 못한 에러를 막는다.

  • isRequired : 필수로 해당 props를 전달하도록 한다. 만약 전달되지 않을 경우 콘솔에 에러가 뜬다 ( 단, 렌더링은 됨 )

  • import PropTypes from "prop-types"; 해야한다.

  • 부모 컴포넌트
    -> props로 전달하는 값이 문자열인 경우에는 ""(따옴표)로 감싸 전달하지만, 이외의 타입인 경우 {}(중괄호)에 감싸서 전달한다.

function App() {
	<FunProps weather={true} feeling="exciting" />
}
import PropTypes from "prop-types";

export default function FunProps {
	return (
    	<>
       		<div>weather props로 전달받은 데이터 : {weather}</div>
      		<div>feeling props로 전달받은 데이터 : {feeling}</div>
      		<div>오늘의 날짜는 {date} 입니다.</div>
        </>
    );
}

FunProps.propTypes {
	weather : PropTypes.string,
    feeling : PropTypes.string,
    date : PropTypes.number.isRequired,
};

-> weather의 타입을 string으로 정했는데, boolean 타입으로 작성해서 콘솔에서 오류가 뜨고 있다. ( 단, 렌더링은 됨! )

  • 부모 컴포넌트 props 값 변경
function App() {
	<FunProps feeling="exciting" />
}

-> date를 isRequired로 타입을 설정했는데, 값을 아예 쓰지 않아서 오류가 났다. ( 렌더링 돼서 콘솔에 undefined는 뜬다.)

6) props.children

  • 부모 컴포넌트에서 자식 컴포넌트를 호출할때 태그 사이에 작성한 content를 도출한다.

문자열 전달

  • 부모컴포넌트
function App() {
	<FunProps name="장원영">예쁘다<FunProps/>
}
export default function Funprops(props) {
	return (
    	<>
        	<div>{props.name}</div>
            <div>{props.children}</div>
        </>
    );
}

함수 전달

  • 부모 컴포넌트
function App() {
const sayHi = () => {
	alret("안녕");
}; 
	<FunProps>{sayHi}</FunProps>
}
export default function FunProps(props) {
	return <div onClick={props.children}>클릭해</div>;
}

많은 요소 전달

function App() {
	<FunProps>
      <div>안녕</div>
      <div>여러요소를 전달하자</div>
    </FunProps>
}
export default function FunProps(props) {
	return <div>{props.children}</div>
}

3. 클래스형 컴포넌트

function App() {
	<ClassProps drink="아메리카노" payment="카드" price={4000} />
}
import React, { Component } from "react";

export default class ClassProps extends Component {
	render() {
    console.log(this.props);
    // this.props : 객체 
    // {drink: '아메리카노', payment: '카드', price: 4000}
    return (
    	<div>주문하신 음료는 {this.props.drink}이고, 결제는 {this.props.payment}로 하시나요? 가격은 {this.props.price}원 입니다.</div>
    );
    }
}

1) default 값 설정하기

  • static 키워드를 사용한다.
  • 컴포넌트 내부에 선언하되, render안에만 안들어가면 된다.
  • 부모 컴포넌트
function App() {
	<ClassProps drink="아인슈페너" payment="현금" />
}
  • 자식 컴포넌트
import React, { Component } from "react";

export default class ClassProps extends Component {
	render() {
    
    return (
    	<div>주문하신 음료는 {this.props.drink}이고, 결제는 {this.props.payment}맞으실까요? 가격은 {this.props.price}원 입니다.{</div>
    );
  }
}

static defaultProps = {
	price : 8500,
};

2) propsTypes

  • 함수형과 동일하게 적용한다.
  • import PropTypes from "prop-types"; 해야한다.
import PropTypes from "prop-types";
export default class ClassProps extends Component {
	render() {
    	return(
    	);
    }
}

ClassProps.propTypes = {
	drink : PropsTypes.string,
    payment : PropsTypes.string.isRequired, 
    price : PropsTypes.number,
};

4. 실습

1) 여러 데이터 사용

  • 부모 컴포넌트
import ProductItem from "./components/ProductItem";

function App() {
	const products = [
    {
      id: 1,
      name: "노트북",
      price: 1000000,
      image: "./img/laptop.jpg",
      description: "고성능 노트북입니다.",
    },
    {
      id: 2,
      name: "스마트폰",
      price: 800000,
      image: "./img/smartphone.jpg",
      description: "최신 스마트폰입니다.",
    },
    {
      id: 3,
      name: "유선키보드",
      price: 20000,
      image: "./img/keyboard.jpg",
      description: "유선 키보드입니다.",
    },
    {
      id: 4,
      name: "블루투스 키보드",
      price: 30000,
      image: "./img/bluetooth-keyboard.jpg",
      description: "사용이 편리한 무선 키보드입니다.",
    },
    {
      id: 5,
      name: "기계식 키보드",
      price: 180000,
      image: "./img/mechanical-keyboard.jpg",
      description: "소리가 매력적인 기계식 키보드입니다.",
    },
    {
      id: 6,
      name: "마우스",
      price: 50000,
      image: "./img/mouse.jpg",
      description: "편리한 이용이 가능한 마우스입니다.",
    },
    {
      id: 7,
      name: "게이밍 마우스",
      price: 80000,
      image: "./img/gaming-mouse.jpg",
      description: "게이밍용 마우스입니다.",
    },
    {
      id: 8,
      name: "32인치 모니터",
      price: 300000,
      image: "./img/monitor-32.jpg",
      description: "32인치의 모니터입니다.",
    },
    {
      id: 9,
      name: "20인치 모니터",
      price: 180000,
      image: "./img/monitor-20.jpg",
      description: "20인치의 키보드입니다.",
    },
  ];
  
  return (
  <div className="App">
  	{products.map((prod)=> (
		<ProductItem prodData={prod} key={prod.id} />
    ))}
  </div>
  );
}

-> 배열인 products를 map으로 한개씩 요소들을 뽑아내 ProdData에 넣고, 고유한 값인 key값도 id를 뽑아내 작성한다.

  • 자식 컴포넌트
export default function ProductList ({ProdData}) {
	return (
    	<div>
        	<div>제품명 : {ProdData.name}</div>
            <div>가격 : {prodData.price}</div>
        </div>
    );
}

2) 여러 데이터 사용 - develop

  • container를 하나 더 만들어서 한단계 추가한다.

  • 최상위 부모 (App.js)

import ProductContainer from "./components/ProductContainer";

function APP() {
	const products = [
    {
      id: 1,
      name: "노트북",
      price: 1000000,
      image: "./img/laptop.jpg",
      description: "고성능 노트북입니다.",
    },
    {
      id: 2,
      name: "스마트폰",
      price: 800000,
      image: "./img/smartphone.jpg",
      description: "최신 스마트폰입니다.",
    },
    {
      id: 3,
      name: "유선키보드",
      price: 20000,
      image: "./img/keyboard.jpg",
      description: "유선 키보드입니다.",
    },
    {
      id: 4,
      name: "블루투스 키보드",
      price: 30000,
      image: "./img/bluetooth-keyboard.jpg",
      description: "사용이 편리한 무선 키보드입니다.",
    },
    {
      id: 5,
      name: "기계식 키보드",
      price: 180000,
      image: "./img/mechanical-keyboard.jpg",
      description: "소리가 매력적인 기계식 키보드입니다.",
    },
    {
      id: 6,
      name: "마우스",
      price: 50000,
      image: "./img/mouse.jpg",
      description: "편리한 이용이 가능한 마우스입니다.",
    },
    {
      id: 7,
      name: "게이밍 마우스",
      price: 80000,
      image: "./img/gaming-mouse.jpg",
      description: "게이밍용 마우스입니다.",
    },
    {
      id: 8,
      name: "32인치 모니터",
      price: 300000,
      image: "./img/monitor-32.jpg",
      description: "32인치의 모니터입니다.",
    },
    {
      id: 9,
      name: "20인치 모니터",
      price: 180000,
      image: "./img/monitor-20.jpg",
      description: "20인치의 키보드입니다.",
    },
  ];
  
	return (
    <div className="App">
		<ProudctContainer products={products} />
    </div>
   );
}
  • 자식 1 (ProductContainer.jsx)
import ProducItem from "./ProductItem";

export default function ProductContainer ({ products }) {
	return (
    	<div>
        	{products?.map((prod)=>(<ProductItem prodData={prod} key={prod.id} />))}
        </div>
    );
} 

?
-> 보통 products라는 props가 전달되지 않는 것은 오류가 발생하지 않지만, products를 사용하는 순간 에러가 발생한다.
-> ?를 사용함에 따라 에러가 발생하지 않게 한다. (단! 디버깅하기 어려움)
key
-> 다른 요소와 겹쳐지지 않고 고유한 값을 가져야 한다.
-> 배열의 요소 중 고유한 값이 없다면 최후의 수단으로 index를 사용한다.
-> 각 상품이 수정되거나 순서가 바뀌더라도 key 식별자를 통해 DOM을 효율적으로 업데이트 할 수 있다.

{products?.map((prod, index) => {
	<ProductItem prodData={prod} key={`prod_${index}`} />
})}
  • 자식 2 (ProductItem.jsx)
export default function ProductItem ({ ProdData }) {
	return (
   		<div>
      		<div>제품명 : {prodData.name}</div>
      		<div>가격 : {prodData.price}</div>
    	</div>
    );
}
```
profile
암튼 해보는 개발자호소인

0개의 댓글