개발자를 향해...

[ReactJS로 영화 웹 서비스 만들기] #2 JSX & PROPS 본문

웹 자바스크립트 공부/ReactJS + node.js

[ReactJS로 영화 웹 서비스 만들기] #2 JSX & PROPS

eugeneHwang1124 2021. 2. 5. 19:01
728x90
반응형

본 내용은 노마드코더 - ReactJS로 영화 웹 서비스 만들기 를 수강하며 작성되었습니다.

 

 

브라우저에 실행 화면을 계속 띄우고 싶다면 localhost를 계속 유지하고 refresh할 수 있고 이를 위해 npm start를 실행한 후 console을 종료하면 안된다. 

 

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);


reportWebVitals();

위의 <App />은 컴포넌트component라고 부른다. 리액트는 component와 함께 동작한다. 개발자는 이 데이터를 보여주는 component를 보기 좋게 만들어야한다. 

component는 HTML을 반환하는 함수이다. react는 component를 이용해 HTML처럼 작성하려는 경우 필요하다. javascript와 HTML 사이의 이런 조합을 jsx라 부른다. jsx는 react에서만 사용된다. 이때 jsx의 사용을 위해 파일에 반드시 import React from 'react'를 넣어주어야 react가 jsx가 있는 component를 사용하는 것을 이해할 수 있다. 

 

이제 Potato.js라는 파일을 생성하고 코드를 작성해보자

import React from 'react';

function Potato(){ //함수명은 대문자로 시작해야한다.
    return (
        <h3>I love potato</h3>
    )
}

export default Potato; //export해야 외부에서 사용이 가능하다.

이렇게 선언하고 Potato를 사용해보자. Potato를 사용하려는 파일의 상단에 import Potato from './Potato';를 추가한 후 컴포넌트를 불러서 사용해보자.

만약 index.js에 다음과 같이 코드를 작성하고 실행해보면 에러가 발생한다.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Potato from './Potato';

ReactDOM.render(
  // <React.StrictMode>
    <App />
    <Potato/>
  // </React.StrictMode>
  ,
  document.getElementById('root')
);


reportWebVitals();

왜냐하면 이건 react application이 하나의 component 만을 rendering 해야하기 때문에 App이나 Potato 둘 중 하나만 있어야한다. 여기서는 그 컴포넌트가 App이다. 따라서 Poatato를 App안에 넣어주자.

import React from 'react';
import Potato from './Potato';

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

export default App;

그리고 개발자 도구에서 소스코드를 보면 react는 component를 가져와서 Browser가 이해가능한 일반 HTML로 바꾸어준 것을 볼 수 있다.

여기까지가 jsx의 역할에 대해 절반을 설명했다.

 

중간 정리: react application은 한번에 하나의 component만을 rendering할 수 있다.따라서 모든 것들은 application 안에 들어가야한다. 이 application 안에 무수히 많은 component를 import를 통해 넣을 수 있다.

 

이제 Potato 파일을 지우자. 그리고 App에 같은 함수를 작성해보자.

import React from 'react';

function Potato(){
  return (<h2>I love potato</h2>)
}

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

export default App;

그러면 Potato.js파일이 있었을 때와 같은 결과화면이 출력된다. jsx에서 두번째로 중요한 부분은 component에 정보를 보낼 수 있다는 점이다. react에서는 재사용이 가능한 component를 만들 수 있다. 예를 들어 영화 목록을 보여주는 화면을 만들고 싶으면 수동으로 모든 영화에 대해 이름과 포스터만 다르고 같은 코드를 반복해 작성할 필요 없이 동적으로 카드를 할당할 수 있다. 이제 component(parents component)에서 component(child component)로 영화정보, 포스터 이미지와 같은 데이터를 보내서 사용하는 방법을 알아보자.

Potato 함수를 Food로 바꾸고 App 함수의 호출부분을 <Food name='kimchi'/>로 바꾸자. 여기서 name은 HTML의 class와 같은 역할이다. name은 jsx로 기본적으로 어떤것의 이름과 속성을 따옴표와 텍스트를 쓰는 방식이다. 이 코드를 통해 Food component에 kimchi라는 value로 prop name을 부여한 것이다.  props의 수는 무제한 가능하다.

<Food name='kimchi' favorit="1" somethings={ture} papapapa={["hello",1,2,3,4,5,6,false]}/>

만약 Food component로 정보를 보내려하면 react는 이 모든 props를 가져온다. 그리고 Food function component의 인자(argument)로 이 속성들을 넣어줄 것이다. 그리고 이런 props를 출력해보면 다음과 같이 출력된다.

function Food(props){
  console.log(props);
  return (
  <h2>I love potato</h2>
  )
}

function Food(props)로 가져올 수도 있지만 function Food( {name} )로 가져올 수도 있다. props로 가져온 object 내에 존재하기 때문이다.  따라서 아래와 같이 가져온 변수를 쓸 수도 있다.

import React from 'react';

function Food(props){  //or function Food({name})
  console.log(props);
  return (
  <h2>I love {props.name}</h2> //or <h2>I love {name}</h2>
  )
}

function App() {
  return (
    <div>
      Hello!!!!!!
      <Food name='kimchi' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
    </div>
  );
}

export default App;

이런 방법을 이용해서 동적으로 코드를 재사용할 수 있다.

import React from 'react';

function Food(props){
  console.log(props);
  return (
  <h2>I love {props.name}</h2>
  )
}

function App() {
  return (
    <div>
      Hello!!!!!!
      <Food name='kimchi' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
      <Food name='라면' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
      <Food name='김치우동' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
      <Food name='삼겹살' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
      <Food name='떡볶이' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
      <Food name='샐러드' favorit="1" somethings={true} papapapa={["hello",1,2,3,4,5,6,false]}/>
    </div>
  );
}

export default App;

 

중간 정리 : props는 다른 component의 argument로 전달된다. 이렇게 전달된 argument를 component 내부에서 쓸 수 있다.

 

 

위와 같이 같은 코드를 <Food~~ 형식으로 복사붙여넣기를 하는것은 비효율적이고 우리가 가지고있지 않은 데이터는 추가할 수가 없다. 따라서 이번에는 동적 데이터를 추가하는 방식을 배워보자. FoodILike라는 배열에 API에서 가져온 데이터를 넣는다고 생각해보자. 그리고 가져온 배열로 음식이름의 위치에 랜더링rendering해보자.

const FoodILike=[
  {
    name: "떡볶이",
    image:""
  },
  {
    name:"라면",
    image:""
  },
  {
    name:"에그마요 salad",
    image:""
  },
  {
    name:"들깨칼국수",
    image:""
  },
  {
    name:"보리비빔밥",
    image:""
  }
]

자바스크립트에는 map이라는 것이 있다. map은 각 아이템에서 함수를 실행하는 array를 가지는 javaScript 함수이며 그 함수의 결과를 가지는 array를 리턴한다.

const friends =['john', 'sam', 'lg','ej'];

에서 friends.map( )안에 current라는 인자를 넣어보자.

friends.map(current => { //구 javascript에서-> friends.map(function (current) {
	console.log(current);
    return 0;
})

이렇게 하면 모든 friends에 대해 함수를 실행시킨다. 만약 저 이름들을 출력할 때 뒤에 하트를 붙이고 싶다면,

friends.map(current => { //구 javascript에서-> friends.map(function (current) {
	console.log(current+"❤");
    return 0;
})

다음과 같이 출력된다. [0,0,0,0]은 return값이 0이기 때문이다. return 값이 없으면 undefined가 나온다.

이렇게 변형도 가능하다.

다시 코드로 돌아와 리스트로 만들어준 음식 목록을 다음과 같이 사용해보자.(image에는 이미지 주소를 넣어주었다)

import React from 'react';

const foodILike=[
  {
    name: "떡볶이",
    image:""
  },
  {
    name:"라면",
    image:""
  },
  {
    name:"에그마요 salad",
    image:""
  },
  {
    name:"들깨칼국수",
    image:""
  },
  {
    name:"보리비빔밥",
    image:""
  }
]

function Food(props){
  console.log(props);
  return (
  <h2>I love {props.name}</h2>
  )
}

function App() {
  return (
    <div>
      Hello!!!!!!
      {foodILike.map(dish => <Food name={dish.name}/>)}
    </div>
  );
}

export default App;

여기서 dish는 object이다. 이 object 내부에서 object.name과 object.image가 존재한다.

이제 여기에 사진도 추가해보자.

import React from 'react';

const foodILike=[
  {
    name: "떡볶이",
    image:""
  },
  {
    name:"라면",
    image:""
  },
  {
    name:"에그마요 salad",
    image:""
  },
  {
    name:"들깨칼국수",
    image:""
  },
  {
    name:"보리비빔밥",
    image:""
  }
]

function Food({name, image}){
  return (
    <div>
      <h2>I love {name}</h2>
      <img src={image} width="200px"/>
    </div>
  )
}

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

export default App;

이제 Food 컴포넌트를 호출하는 부분을 함수로 빼보자. 

import React from 'react';

const foodILike=[
  {
    name: "떡볶이",
    image:""
  },
  {
    name:"라면",
    image:""
  },
  {
    name:"에그마요 salad",
    image:""
  },
  {
    name:"들깨칼국수",
    image:""
  },
  {
    name:"보리비빔밥",
    image:""
  }
]

function Food({name, image}){
  return (
    <div>
      <h2>I love {name}</h2>
      <img src={image} width="200px"/>
    </div>
  )
}

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

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

export default App;

ㅇ   . 

import React from 'react';

const foodILike=[
  {
    id:1,
    name: "떡볶이",
    image:""
  },
  {
    id:2,
    name:"라면",
    image:""
  },
  {
    id:3,
    name:"에그마요 salad",
    image:""
  },
  {
    id:4,
    name:"들깨칼국수",
    image:""
  },
  {
    id:5,
    name:"보리비빔밥",
    image:""
  }
]

function Food({name, image}){
  return (
    <div>
      <h2>I love {name}</h2>
      <img src={image} width="200px" alt={name}/>
    </div>
  )
}

function renderFood(dish){
  // console.log(dish)
  return <Food key={dish.id} name={dish.name} image={dish.image}/>
}

function App() {
  return (
    <div align="center">
      {foodILike.map(renderFood)}
    </div>
  );
}

export default App;

이제 npm i prop-types를 설치한다. 이건 내가 전달받은 props가 내가 원하는 props인지를 확인해준다.  이 propTypes로 props를 확인하는 코드를 넣어준다.

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

이처럼 PropeType는 string, number 뿐만 아니라 array인지, boolean인지 true인지 false인지 object인지 , 존재하는지 없는지 확인할 수 있다. 

반응형