Movie app 만들기(2)

배고픈메꾸리·2020년 10월 6일
0
post-thumbnail


컴포넌트


전 포스트에서 만들었던 index.js
ReactDOM.render(<App/>, document.getElementById("root") 에서 <App/>컴포넌트라고 부른다. 컴포넌트는 기본적으로 HTML을 반환하는 함수이고, 우리는 이러한 컴포넌트를 사용하고자 할 때 <App/> 의 형태로 사용하는 것이다.

React는 이렇듯 컴포넌트를 사용해서 HTML처럼 작성하려는 경우에 필요하다. 그리고 이러한 javascript와 HTML의 조합을 JSX라고 한다.


컴포넌트 생성


src 폴더 아래에 Potato.js 를 만들자.

<Potato.js>
import React from "react";

function Potato(){
  return <h3>I love potato</h3>;
}
export default Potato;

컴포넌트를 작성할 때 마다 import React from "react"; 를 써줘야 하는 점과 함수의 시작은 대문자로 시작하는 점에 주의하자.

이렇게 만든 Potato 를 어떻게 사용할까? index.js 에 Potato를 import 해주고 ReactDOM.render<Potato/> 를 써주면 좋겠지만 React application은 하나의 컴포넌트만을 렌더링해야하기 때문에 불가능하다. 그렇기 때문에 우리는 App컴포넌트 안에 Potato 컴포넌트를 넣어주는 방식으로 작성해야 한다.

<App.js> 
import React from "react";
import Potato from "./Potato";

function App() {
  return (
    <div>
      <h1>Hello!!</h1>
      <Potato />
    </div>
  );
}

export default App;

결과를 보면 react가 컴포넌트를 가져와서 브라우저가 이해할 수 있는 평범한 HTML로 만들어 준 것을 확인할 수 있다.

컴포넌트를 어떻게 사용하는지 알았으면 Potato.js를 지우고 App.js를 다음과 같이 수정하자.

<App.js>
import React from "react";

function Potato() {
  return <h1>I like Potato</h1>;
}

function App() {
  return (
    <div>
      <h1>Hello!!</h1>
      <Potato />
    </div>
  );
}

export default App;

결과는 동일한 것을 확인할 수 있다.



컴포넌트에 정보 보내기


react가 멋진 이유는 재사용 가능한 컴포넌트를 만들 수 있다는 점이다.

App.js에서 Potato를 Food로 변경하자. 그런 다음 App 컴포넌트에서 Food 컴포넌트로 정보를 보내고 Food 컴포넌트에서 전달받은 정보를 사용하는 방법에 대해서 알아보자

<App.js>
  
...

function App() {
  return (
    <div>
      <h1>Hello!!</h1>
      //Food 컴포넌트에 property를 전달하자
      <Food menu = "kimchi" /> 
    </div>
  );
}

export default App;

App 컴포넌트에서

  1. Food 컴포넌트에
  2. menu라는 이름의 property를
  3. kimchi라는 value로 전달하였다.

Food 컴포넌트에서 value를 제대로 전달받았는지 확인하기 위해 인자에 props를 추가하고 console.log(props); 로 확인해보자

<App.js>
import React from "react";

function Food(props) {
  console.log(props);
  return <h1>I like Potato</h1>;
}

function App() {
  return (
    <div>
      <h1>Hello!!</h1>
      <Food menu ="kimchi" />
    </div>
  );
}

export default App;

확인해보면 {menu : kimchi} 라는 object가 제대로 전달된 것을 확인할 수 있다. 다음으로 전달받은 값을 출력하는 방법을 알아보자.

Food의 인자에 {menu}를 넣어주고 I like {menu}라고 변경해주자. 참고로 {menu}props.menu와 동일하다.

<App.js>
import React from "react";

function Food({menu}) {
  return <h1>I like {menu}</h1>;
}

/* 동일
function Food(props) {
  return <h1>I like {props.menu}</h1>;
}
*/

function App() {
  return (
    <div>
      <h1>Hello!!</h1>
      <Food menu ="kimchi" />
    </div>
  );
}

export default App;


동적 컴포넌트 생성


동적으로 정보를 받아서 출력하는 컴포넌트를 생성해보자. 음식 object를 저장하는 foodILike 변수를 작성하자

<App.js>
  
  ...

const foodILike = [
  {
    name: "Kimchi",
    image:
      "https://kstory365.files.wordpress.com/2015/01/kimchi-01-cabbage.jpg",
  },
  {
    name: "bulgogi",
    image:
      "https://www.bloter.net/wp-content/uploads/2017/04/yoons_bulgogi-3.jpg",
  },
];

function App() {
  
  ...
  // 이미지 출처 : duckduckgo

foodILike에 있는 object들을 받아와서 Food 컴포넌트에서 값을 동적으로 출력해볼텐데 그 전에 map 함수에 대해서 알아보자

map 함수

map 함수는 배열의 각 원소별로 function을 적용하여 function의 결과값을 갖는 배열을 리턴한다.
간단한 예제를 생각해보자. 다음과 같이 sunk라는 배열이 있다.

const sunk = ["s" , "u" , "n" , "k" ];

이 배열을 통해 s1 , u2 , n3 , k4 라는 배열을 얻고 싶다고 할 때, map함수를 통하여 쉽게 구현이 가능하다.

let i = 0;

sunk.map( (potato) => {
  i++;
  return potato + i ;
});
// ["s1", "u2", "n3", "k4"]

(potato는 각 원소를 나타낸다.)

이를 응용하여 foodILike 의 object들을 Food 컴포넌트로 전달하여 화면에 출력해보자.
먼저 App 컴포넌트를 다음과 같이 변경하자

<App.js>
  ...

function App() {
  return (
    <div>
      {foodILike.map((potato) => (
        <Food menu={potato.name} picture={potato.image} />
      ))}
      
      /* 하다가 알게된 점 : 한줄짜리는 { return } 대신    ( ) 으로 대체 가능
      
      {foodILike.map((potato) => {
        return <Food menu={potato.name} picture={potato.image} />
      })}
      
      */
      
    </div>
  );
}

export default App;

이를 통해 foodILike의 각 원소별로 menu , picture에 매칭되어서 Food 컴포넌트로 전달된다.
이제 Food 컴포넌트에서 props로 받아서 출력하는 코드를 작성하자

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

여기서 정상적으로 작동하지만 개발자 도구를 열어보면 다음과 같은 경고들이 나오는 것을 확인할 수 있다.

먼저 빨간색 경고메시지부터 해결해보자. list 내의 child는 유일한 key prop을 가져야 한다고 하는 것인데, 모든 react의 element들은 유일해야하는데 이것들을 list안으로 집어넣으면 유일성을 잃어버리기 때문이라고 한다.

이 경고를 해결하기 위해 코드를 다음과 같이 수정하자

<App.js>
  
  ...

//변경
const foodILike = [
  {
    id : 1,
    name: "Kimchi",
    image:
      "https://kstory365.files.wordpress.com/2015/01/kimchi-01-cabbage.jpg",
  },
  {
    id : 2,
    name: "bulgogi",
    image:
      "https://www.bloter.net/wp-content/uploads/2017/04/yoons_bulgogi-3.jpg",
  },
];

function App() {
  return (
    <div>
      {foodILike.map((potato) => {
        return (
          //변경
          <Food key={potato.id} menu={potato.name} picture={potato.image} />
        );
      })}
    </div>
  );
}

export default App;

확인해보면 경고메시지가 사라진 것을 확인할 수 있다. 보면 key prop은 Food 컴포넌트로 전달되지 않는다. key prop은 react 내부에서 사용하기 위해 사용하는 것이기 때문이다.

다음은 노란색 메시지를 해결해보자. 해당 메시지는 이미지파일이 렌더링되지 못했을 때 나타나는 문자열 값을 지정해 주지 않아서 발생한 메시지이다. App.js 에서 Food의 img태그에 alt 속성을 추가하자.

<App.js>
  
 function Food({ menu, picture }) {
 return (
   <div>
     <h2>I like {menu}</h2>
     <img src={picture} alt={"sss"} />
   </div>
 );
}

...

이렇게 수정하면 메시지가 모두 사라진 것을 확인할 수 있다.

출처 : Do it! 리액트 프로그래밍 정석 / 노마드 코더

profile
FE 개발자가 되자

0개의 댓글