React

노마드코더 : React(영화 웹 서비스) - 3. 컴포넌트 많이 만들기, map()함수, 경고 메세지 수정, prop-types 도입 (by. 음식 앱)

식초 2020. 11. 28. 00:40

비슷한 컴포넌트 여러 개 만들기

앞에서 컴포넌트를 많이 만들때 <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 propsFood 컴포넌트에 전달하자.

 

 

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

 

facebook/prop-types

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

github.com