본문 바로가기
Project/REACT

10 - 발전된 컴포넌트 만들기(2)

by Elfen Lied 2020. 12. 10.
반응형
  • 음식 앱 만지고 고치기
  • 음식 앱에 prop-types 도입하기

 

1. 음식 앱 만지고 고치기

코드블럭처럼 코드를 수정해준다.

function App() {
  return (
    <div>
      {foodLike.map(dish => (
        <Food name={dish.name} picture={dish.image} />
      ))}
    </div>
  );
}

===========================================

// 다음 처럼 변경한다.
function App() {
  return (
    <div>
      {foodLike.map(renderFood)}
    </div>
  );
}

 

 

- renderFood() 함수를 정의한다.

 

앞선 코드 위에 renderFood() 함수를 정의 해준다.

function renderFood(dish) {
  return <Food name={dish.name} picture={dish.image} />;
}


function App() {
  return (
    <div>
      {foodLike.map(renderFood)}
    </div>
  );
}

map() 함수의 첫 번째 인자로 전달한 화살표 함수를 밖으로 빼서

일반 함수 rederFood() 로 바꾼것 뿐이라 바뀌는 것은 없다.

 

만약 renderFood() 함수를 화살표 함수로 바꾸고 싶다면 아래 코드블럭 처럼 써주자.

const renderFood = dish => <Food name={dish.name} picture={dish.image} />;

 

- 현재까지의 코드 상태 -

import React from 'react';

function Food({ name, picture }) {
  return (
    <div>
      <h2>I like {name} </h2>
      <img src={picture} />
    </div>
  );
}

const foodLike = [이미지 주소들];

function renderFood(dish) {
  return <Food name={dish.name} picture={dish.image} />;
}

function App() {
  return (
    <div>
      {foodLike.map(renderFood)}
    </div>
  );
}

export default App;

 

- map() 함수 반환값 확인

console.log(foodLike.map(...)); 추가해준다.

function App() {
  console.log(foodLike.map(renderFood));
  return (
    <div>
      {foodLike.map(renderFood)}
    </div>
  );
}

 

※개발자 도구에서 console.log 가 안보이고,

[HMR] Waiting for update signal from WDS

https://simfairy.tistory.com/161

 

 

Array(5)가 보인다.

화살표를 눌러서 펼쳐보면 사진 처럼 나온다.

이게 map() 함수가 반환한 리액트 컴포넌트다.

 

반환값을 확인하기 위해서 한것이니 확인을 했다면 코드를 원상태로 돌리자.

 

삭제
function renderFood(dish) {
  return <Food name={dish.name} picture={dish.image} />;
}


코드 원상 복구
function App() 
  return (
    <div>
      {foodLike.map(dish => (
      	<Food name={dish.name} picture={dish.image} />
      ))}
    </div>
  );
}
  • 삭제 라고 적힌 코드는 지워주고,
  • 코드 원상 복구라고 적힌 부분은 다시 코드블럭처럼 돌려놓는다.

 

개발자 도구에 Warning: Each child in a list should have a unique "key" prop. 오류가 보일텐데

이유는 리스트의 각 원소는 유일한 key prop을 가져야 한다고 한다.

배열 속성에 key 값이 없어서 이런 오류가 나온것.

리액트 원소는 유일해야 하는데 리스트에 포함되면서 유일성이 없어졌다.

 

 

- 해결을 위해서는 foodLike 배열 원소에 id 값을 추가해준다.

const foodLike = [
  {
    id: 1,
    name: 'Kimchi',
    image: 'https://cdn.pixabay.com/photo/2019/07/25/01/35/kimchi-4361465_1280.jpg',
  },
  {
    id: 2,
    name: 'Samgyeopsal',
    image: 'https://cdn.pixabay.com/photo/2017/05/18/10/48/pork-2323228_1280.jpg',
  },
  .
  .
  .
  {
    id: 5
    name: 'Kimbap',
    image: 'https://cdn.pixabay.com/photo/2015/03/24/07/07/kim-rice-687172_1280.jpg',    
  },
];

id를 추가하는 이유는 컴포넌트가 서로 다르다는 것을 알려주기 위해

컴포넌트에 key props를 추가한다.

 

 

- Food 컴포넌트에 key props를 추가한다.

{dish.id}를 전달하면 된다.

function App() 
  return (
    <div>
      {foodLike.map(dish => (
      	<Food key={dish.id} name={dish.name} picture={dish.image} />
      ))}
    </div>
  );
}

리액트 앱을 다시 실행하고 콘솔창을 열어보면 오류가 없어졌다.

 

※단, key props는 리액트 내부에서 사용되는 특수한 prop라서

Food 컴포넌트에 직접 전달되지 않는다.

 

만약 alt-text 관련 오류가 보인다면

function Food({ name, picture }) {
  return (
    <div>
      <h2>I like {name} </h2>
      <img src={picture} alt={name} />
    </div>
  );
}

img src={picture} 뒤에 alt={name} 를 추가하자.

블로그 글 9 - 발전된 컴포넌트 만들기(1) 에서 언급했음.

 

 

2. 음식 앱에 prop-types 도입하기

 

- props 검사하기

 

- 음식 데이터에 rating(평점) 추가

 

foodLike 배열 각 요소에 rating을 추가하자.

자료형은 Number 다.

const foodLike = [
  {
    id: 1,
    name: 'Kimchi',
    image: 'https://cdn.pixabay.com/photo/2019/07/25/01/35/kimchi-4361465_1280.jpg',
    rating: 5,
  },
  {
    id: 2,
    name: 'Samgyeopsal',
    image: 'https://cdn.pixabay.com/photo/2017/05/18/10/48/pork-2323228_1280.jpg',
    rating: 4.3,
  },
  .
  .
  .
  {
    id: 5,
    name: 'Kimbap',
    image: 'https://cdn.pixabay.com/photo/2015/03/24/07/07/kim-rice-687172_1280.jpg',
    rating: 4.6,
  },
];

rating은 준비됐고, props 자료형을 검사할 수 있는 prop-types를 설치한다.

 

 

- prop-types 설치

 

1.

터미널에서 코드블럭에 있는 명령어를 입력한다.

경로는 현재 react 프로젝트가 있는곳에서 한다.

npm install prop-types

 

2.

package.json을 연다. 

"prop-types": 부분이 보이면 잘 설치 된것.

prop-types은 전달 값이 내가 원하는 값인지 확인 해준다.

어떠한 값이 전달 되야한다고 정의 할 수 있다.

 

 

- prop-types 적용

App.js 파일 맨위에 다음을 추가해준다.

 

import PropTypes from 'prop-types';

 

이어서 다른 부분에도 코드들을 추가해준다.

import React from 'react';
import PropTypes from 'prop-types';

function Food({ name, picture, rating }) {
  return (
    <div>
      <h2>I like {name} </h2>
      <h4>{rating}/5.0</h4>
      <img src={picture} alt={name} />
    </div>
  );
}

const foodLike = [...];

function App() {
  return (
    <div>
      {foodLike.map(dish => (
        <Food key={dish.id} name={dish.name} picture={dish.image} rating={dish.rating} />  
      ))}
    </div>
  );
}

export default App;

여기까진 prop-types를 적용하진 않은 상태다.

그래도 rating props로 전달한 값은 출력된다.

 

이제 prop-types를 적용해보자.

function App() {
  return (
    <div>
      {foodLike.map(dish => (
        <Food key={dish.id} name={dish.name} picture={dish.image} rating={dish.rating} />  
      ))}
    </div>
  );
}

Food.propTypes = {
  name: PropTypes.string.isRequired,
  picture: PropTypes.string.isRequired,
  rating: PropTypes.string.isRequired,
};

export default App;

Food.propTypes = {...}를 추가한다.

 

1. 자료형 오류

그리고 앱을 다시 실행해보면 문제없이 실행되는데 콘솔창을 보면 경고 메시지가 뜬다.

Warning: Failed prop type: Invalid prop `rating` of type `number` supplied to `Food`, expected `string`.

 

앞서 추가한 코드에 rating: PropTypes.string.isRequired 다.

string은 '문자열', isRequired는 '필요하다' 라는 뜻이다.

 

근데 지금 넘겨준 자료형은 Number다. 그래서 오류가 뜬것.

 

 

- prop-types 경고 해결

Food.propTypes = {
  name: PropTypes.string.isRequired,
  picture: PropTypes.string.isRequired,
  rating: PropTypes.number.isRequired,
};

rating: propTypes.string 이었던걸 number로 바꾼다.

 

 

2. 이름 값 오류

function App() {
  return (
    <div>
      {foodLike.map(dish => (
        <Food key={dish.id} name={dish.name} image={dish.image} rating={dish.rating} />  
      ))}
    </div>
  );
}

<Food picture={} 를 image={}로 바꿔보자

picture가 포함되어야 하는데 찾을수 없다는 오류를 보여준다.

그리고 이미지들도 표시 되지않는다.

다시 코드를 원래대로 돌려놓자.

function App() {
  return (
    <div>
      {foodLike.map(dish => (
        <Food key={dish.id} name={dish.name} picture={dish.image} rating={dish.rating} />  
      ))}
    </div>
  );
}

 

 

- rating: 의 .isRequired를 제거해보자

Food.propTypes = {
  name: PropTypes.string.isRequired,
  picture: PropTypes.string.isRequired,
  rating: PropTypes.number
};

이제 rating props는 필수가 아니어도 되는 항목이란 뜻이다.

단, 값이 전달될 때는 자료형이 number이긴 해야함.

 

 

- 현재 상태 코드 -

import React from 'react';
import PropTypes from 'prop-types';

function Food({ name, picture, rating }) {
  return (
    <div>
      <h2>I like {name} </h2>
      <h4>{rating}/5.0</h4>
      <img src={picture} alt={name} />
    </div>
  );
}

const foodLike = [
  {
    id: 1,
    name: 'Kimchi',
    image: 'https://cdn.pixabay.com/photo/2019/07/25/01/35/kimchi-4361465_1280.jpg',
    rating: 5,
  },
  {
    id: 2,
    name: 'Samgyeopsal',
    image: 'https://cdn.pixabay.com/photo/2017/05/18/10/48/pork-2323228_1280.jpg',
    rating: 4.3,
  },
  {
    id: 3,
    name: 'Bibimbap',
    image: 'https://cdn.pixabay.com/photo/2017/08/08/09/44/food-photography-2610863_1280.jpg',
    rating: 4.9,
  },
  {
    id: 4,
    name: 'Doncasu',
    image: 'https://cdn.pixabay.com/photo/2016/09/23/23/23/restaurant-1690696_1280.jpg',
    rating: 4.2,
  },
  {
    id: 5,
    name: 'Kimbap',
    image: 'https://cdn.pixabay.com/photo/2015/03/24/07/07/kim-rice-687172_1280.jpg',
    rating: 4.6,
  },
];

function App() {
  return (
    <div>
      {foodLike.map(dish => (
        <Food key={dish.id} name={dish.name} picture={dish.image} rating={dish.rating} />  
      ))}
    </div>
  );
}

Food.propTypes = {
  name: PropTypes.string.isRequired,
  picture: PropTypes.string.isRequired,
  rating: PropTypes.number.isRequired,
};

export default App;

 

 


prop-types의 다양한 사용법을 알고 싶다면

prop-types 공식문서에 usage 부분을 보고 참고하자.

github.com/facebook/prop-types

 

facebook/prop-types

Runtime type checking for React props and similar objects - facebook/prop-types

github.com

 

반응형

댓글