비슷한 컴포넌트 여러 개 만들기
앞에서 컴포넌트를 많이 만들때 <Food />,<Food />,... 여러개 만들었다.
이것은 비효율적이다.
만약 음식이 1000개이면 반복 작성하고 fav props에도 다른 값을 입력해야 한다.
서버에서 데이터를 받아 출력하는 경우, 음식 데이터의 개수를 알 수 없다면 더 문제가 된다.
음식 데이터 만들기
서버에서 데이터를 받았다고 가정하고, 데이터를 출력하는 방법을 알아본다.
foodILike라는 변수를 만들고, 빈 배열 할당한다.
Food 컴포넌트는 모두 삭제한다.
서버에서 데이터 넘어온다 상상하며 배열에 코드를 넣는다.
image 키값은 인터넷에서 찾은 이미지의 주소 복붙한다. 링크를 이용하면 이미지 손쉽게 출력 가능하다.
name은 음식의 이름이다.
이제 foodILike에 있는 데이터를 이용해서 여러개 컴포넌트를 만들면 된다.
map( )함수로 컴포넌트 많이 만들기
foodILike에 있는 데이터로 컴포넌트 여러개 만들려면
자바스크립트 함수 map( )의 사용법을 알아야 된다.
map( )함수 사용법 알아보기
크롬에서 콘솔 열고(F12) 코드 입력한다.
> const friends = ["sigcho", "hororagy", "kang", "korean girl"]
friends에 친구 4명의 이름(문자열)을 배열에 담아 저장한다.
콘솔에 friends를 입력해 보면 다음과 같이 배열 나온다.
> friends
["sigcho", "hororagy", "kang", "korean girl"]
배열 안에 이름(문자열) 각각에 하트를 붙이고 싶다면?
map( )함수를 이용한다.
map( )함수는 배열의 모든 원소마다 특정 작업을 하는 함수를 적용하고, 함수가 반환한 결과를 모아서 배열로 반환한다.
map( )함수의 첫번째 인자로 (특정 작업을 하는) 함수 전달
> friends .map( current => {
console.log( current );
return 0;
} )
sigcho // console.log(current)가 출력한 값(1번째) 반환한 값 아님!!
hororagy // console.log(current)가 출력한 값(2번째)
kang // console.log(current)가 출력한 값(3번째)
korean girl // console.log(current)가 출력한 값(4번째)
[0, 0, 0, 0] friends.map(...)이 최종적으로 반환한 값이다
sigcho, hororagy, kang, korean gilr이 출력된 다음 배열 [0, 0, 0, 0]이 반환된다.
map( )함수의 2가지 특징
1. map()함수의 인자로 전달한 함수는 배열 friends의 원소를 대상으로 실행된다.
2. 그 함수가 반환한 값이 모여 배열이 되고, 그 배열이 map()함수의 반환값이 된다.
map( )함수로 이름에 하트 추가한 배열 만들기
friends .map( )의 인자로 이름 뒤에 하트를 붙여 주는 함수를 전달한다.
함수 인자 이름을 current 대신 friend라고 한다. (꼭 current, friend가 아니어도 된다.)
인자 배열에 들어 있는 원소가 1개씩 전달되면서 함수가 반복 실행된다.
friend에 하트를 더하면 이름 뒤에 하트가 붙은 이름을 원소로 가지는 배열 얻을 수 있다.
> friends .map(function(friend) {
return friend + " ♥";
})
["sigcho ♥", "hororagy ♥", "kang ♥", "korean girl ♥"]
이름 없는 함수를 전달했다. 이름없는 함수의 friend에는 friends 배열의 원소가 하나씩 넘어오고, 그 원소에 하틀르 붙여서 반환한다.
map( )함수로 Food 컴포넌트 많이 만들어보기
foodILike 배열을 확인하면서 map( )함수를 어떻게 적용할지 확인하기!
foodILike .map( )과 같이 작성하고, map( )함수에 전달할 인자에는 dish => <Food />와 같이 컴포넌트를 반환하는 함수를 전달하면 된다. dish에는 배열에 있는 원소인 객체 [name: '...', image: '...']가 하나씩 넘어온다.
dish.name, dish.image 같은 방법으로 컴포넌트에 전달한다.
map( )함수를 foodILike배열에 적용하여 코드를 작성하자
<h1>Hello</h1>은 삭제하고, {foodILIke.map(...)}을 추가한다.
Food 컴포넌트에서 받는 인자를 {name}으로 수정한다.
결국 map( )함수는 [ <Food name ={...} />, ... ]와 같이 Food 컴포넌트 원소 5개를 가진 배열을 반환한다.
음식 이름 5개가 화면에 표시된다.
map( )함수의 첫번째 인자로 넘어가는 함수의 첫번째 인자인 dish에는 foodILike의 원소가 하나씩 넘어간다.
Food 컴포넌트에 음식 이미지 출력하기
Food 컴포넌트에 picture props 추가한다. picture props에는 dish.image를 전달한다.
Food 컴포넌트에서 picture props를 받을 수 있도록 코드를 수정하자
h2 엘리먼트로 바꾸고 img 엘리먼트를 추가한다.
div 엘리먼트로 감싼다.
map( )함수를 이용하면 배열에 데이터가 몇 개 있든지 컴포넌트를 여러개 손쉽게 출력할 수 있다.
브라우저 출력 결과
음식 앱 이리저리 만지고, 고쳐보기 (경고 메세지 수정)
리액트와 map()함수가 어던 상호 작용하는지 알아보자.
map( )함수의 인자로 함수 전달하기
{ foodILike.map( renderFood )}로 변경한다.
renderFood( )함수 정의하기
코드는 이전에 작성했던 것과 같다.
map( )함수의 1번째 인자로 전달할 renderFood()함수를 분리했다.
renderFood( )함수를 화살표 함수로 작성하고 싶다면?
const renderFood = dish => <Food name={dish.name} picture={dish.image} />;
map( )함수의 반환값 살펴보기
콘솔로그를 이용해서 map()함수의 반환값 확인해 보자.
Array(5)가 보인다. 배열이 map()함수가 반환한 리액트 컴포넌트이다.
음식앱 원래대로 돌려놓기
이유는 App.js 파일 안에 또다른 함수를 만들지 않기 위해서 이다. 함수가 많으면 나중에 관리하기 어려워진다.
map()함수로 만든 컴포넌트에 key props 추가하기
콘솔에서 경고 메시지가 뜬다.
(Warning : 경고 메세지, 프로그램 실행에 바로 영향을 주지 않지만 가급적이면 수정해야 한다. )
해석하면 '리스트의 각 원소는 유일한 "key" prop을 가져야 한다'고 한다.
리액트 원소가 리스트에 포함되면서 유일성이 사라졌다!
foodILike 배열 원소에 id라는 값을 추가하자
리액트에게 컴포넌트가 서로 다르다는 것을 알려 주는 방법
= 컴포넌트에 key props를 추가하는 것이다.
Food 컴포넌트에 key props를 추가하자
key props의 값으로 {dish.id}를 전달한다.
경고 메세지가 사라진다.
img 엘리먼트에 alt 속성 추가하기
콘솔창에 경고가 뜬다!
alt 속성의 값으로 {name}을 대입한다.
경고 메세지가 사라진다.
음식 앱에 prop-types 도입하기
정의한 props의 값이 컴포넌트에 제대로 전달되지 않으면 어떻게 해야할까?
이런 경우에 props를 검사하는 방법이 필요하다.
foodILike에 데이터를 좀 더 추가해보자.
음식 데이터에 rating 추가하기
rating(평점)을 추가하자. 값의 자료형은 Number이다.
(foodILike에 입력한 값이 데이터베이스에서 넘어온 값이라고 상상하자)
key props는 리액트 내부에서 사용되는 특수한 props라서 Food 컴포넌트에 직접 전달되지 않는다.
prop-types 설치하기
터미널에 명령어 입력 prop-types 설치
> npm install prop-types
package.json 파일 열어서 dependencies 키에 있는 값 확인
prop-types 있는지 확인하기
prop-types는 컴포넌트가 전달받은 props가 정말 내가 원하는 값인지 확인해준다.
prop-types를 통해 미리 'Food 컴포넌트는 반드시 picture prop가 전달돼야 한다'고 정의할 수 있다.
그러면 image props가 전달되는 경우 오류 메세지가 나타난다.
prop-types 적용하기
import PropTypes from 'prop-types';를 App.js 파일 맨 위에 추가하자.
rating props를 Food 컴포넌트에 전달하자.
prop-types를 적용한다. Food.propTypes에 객체를 적어준다.
모든 props는 문자열이고, 반드시 있어야 한다는 조건을 추가한다.
콘솔에는 경고 메세지가 출력된다.
'Food 컴포넌트의 rating props 자료형이 string이어야 하는데 number라서 문제다.'
Food.propTypes의 rating 키값을 다시보자.
'rating에는 string이라는 자료형이 필요하다.'
그런데 우리가 넘겨준 값의 자료형은 Number이기 때문에 경고 메세지가 나타난 것이다.
prop-types 경고 해결하기
rating : PropTypes.number.isRequired 라고 수정한다.
경고 사라진다.
다른 종류의 prop-types 경고 해결하기
prop-types는 또한 props의 이름도 검사해준다.
Food 컴포넌트에 전달하는 picture props의 이름을 Food.propTypes에서 정의한 이름 picture가 아니라 image로 바꾼다.
화면에 사진이 나오지 않고, 경고 메세지가 뜬다.
'Food 컴포넌트에 picture라는 이름의 props가 필요한데 그 값이 undefined다'
prop-types는 이런 식으로 props를 검사한다.
자료형과 그 이름의 값이 전달되었는지 확인한다.
개발자가 실수하지 않도록 예방해 준다.
isRequired의 뜻 살펴보기
평점이 아직 등록되지 않은 영화일 수도 있다.
isRequired는 때에 따라 없어도 된다.
rating의 .isRequired를 제거한다.
rating : PropTypes.number, 로 수정한다.
prop-types의 다양한 사용방법이 궁금하다면?
github.com/facebook/prop-types
'React' 카테고리의 다른 글
노마드코더 : React(영화 웹 서비스) - 5. axios, 영화 API, 데이터 접근해서 화면에 그리기, Movie 컴포넌트 map()으로 만들기, CSS 꾸미기 (0) | 2020.12.03 |
---|---|
노마드코더 : React(영화 웹 서비스) - 4. state와 클래스형 컴포넌트 (0) | 2020.12.01 |
노마드코더 : React(영화 웹 서비스) - 2. 컴포넌트, JSX, Props (0) | 2020.11.26 |
생활코딩 : React - Update & Delete 기능 구현 (0) | 2020.11.18 |
생활코딩 : React - Create 기능 구현 (18~19강) (1) | 2020.11.11 |