본문 바로가기

웹/Front-end

[React] ReactJS로 영화 웹 서비스 만들기 - ② JSX & PROPS

ReactJS로 영화 웹 서비스 만들기 관련 게시글은 모두 

노마드 코더 강의 중 ReactJS로 영화 웹 서비스 만들기 

Do it! 클론 코딩 영화 평점 웹 서비스 책을 참고로 한다.

 

강의 목차는 다음과 같다.

#0 INTRODUCTION

#1 SETUP

#2 JSX & PROPS

#3 STATE

#4 MAKING THE MOVIE APP

#5 CONCLUSIONS

#6 ROUTING BONUS

 


#2 JSX & PROPS

#리액트 동작 원리

App.js파일과 브라우저 출력 화면

 

 

 

앞서 App.js 파일에서 div태그 안에 입력한 텍스트가 브라우저에 출력되었는데, 

public 폴더의 ≫ index.html 파일을 확인해보면 div 태그 사이에 내용이 비어있다.

 

public > index.html

 

리액트는 1) 프로젝트 폴더 (src 폴더)에 작성된 코드를 자바스크립트를 이용해서 해석하고,

2) 해석된 결과물을 index.html에 끼워넣는다. 

 

 

index.js 파일의 

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

App.js파일에서 작성한 코드를, index.html의 아이디가 root인 엘레먼트에 넣어주라는 의미이다.

 

따라서 <div><h1> 헬로 </h1></div>가,

리액트 앱을 실행하면 index.html 파일에 생성되는 것. 

 

리액트 동작 원리 (출처: Do it! 클론 코딩 영화 평점 웹 서비스)

 

 

#리액트 기초개념

1) Component 컴포넌트

src 폴더 > App.js

 

src 폴더 > index.js

 

React는 ✨Component 기반✨이다.

컴포넌트는 html을 반환하는 함수이다.

리액트는 컴포넌트와 함께 동작하고, 리액트 앱은 모두 컴포넌트로 구성된다.

컴포넌트에 데이터를 흘려보내면 설계된대로 UI가 조립되어 사용자에게 보여진다. (☞ 더 알아보기)

 

위의 두 그림에서 살펴보듯, 내가 진행중인 프로젝트는

App.jsfunction App()에서 컴포넌트를 정의하고 (* 컴포넌트 이름은 대문자로 시작),

index.jsimport App from './App'를 통해 App 컴포넌트를 임포트하여 사용한다.

 

 

<App />코드 부분을 통해 컴포넌트를 인식하고, 그 컴포넌트가 반환하는 값을 화면에 그려준다.

 

 

2) JSX 문법

JSX (JavsScriptXML)은 자바스크립트에 XML을 추가해 확장한 문법으로,

HTML과 자바스크립트의 모든 기능을 포함한다.

 

리액트 엔진은 JSX의 XML구조를 분석하여 자바스크립트 함수 코드로 변환한다.

리액트 엔진이 JSX를 자바스크립트로 해석하는 역할을 하기 때문에

개발자가 JSX로 화면 구성에만 집중할 수 있도록 도와준다. →  선언형 화면(Declarative View) 기술

 

3) 컴포넌트 구성요소 - props

데이터 구성 요소 특징
props 프로퍼티 상위 컴포넌트에서 하위 컴포넌트로 전달되는 읽기 전용 데이터
state 컴포넌트의 상태를 저장하고 변경할 수 있는 데이터
context 부모 컴포넌트에서 생성하며 모든 자식 컴포넌트에 전달하는 데이터

props

컴포넌트에서 컴포넌트로 전달하는 데이터.

함수의 매개변수의 개념과 유사.

불리언, 숫자, 배열과 같은 다양한 형태의 데이터를 담을 수 있다.

 

 

props로 컴포넌트에 데이터를 전달하는 방법을 App.js 실습을 통해 살펴보자.


import React from "react";

//Food라는 컴포넌트
function Food(props) {
  return <h1>I like { props.fav }</h1>;
}

function App() {
  return (
    <div>
      <h1>헬로</h1>
      <Food fav="kimchi" />
    </div>
  );
}

export default App;

<Food fav="kimchi" />

Food 컴포넌트에 사용한 props의 이름은 fav이고

fav 프로퍼티에 담은 값이 "kimchi"

 

function Food(props) {

  return <h1>I like { props.fav }</h1>;

}

props에 있는 데이터는 모두 중괄호로 감싸야 하고 (문자열 제외)

객체에 있는 값을 사용하려면 점 연산자(.)을 써야한다. 

따라서, fav 프로퍼티의 값은 props.fav 로 표시해서 사용하고, 중괄호로 감싸 전달해준다.  => { props.fav }

 

BUT

자바스크립트 ES6의 문법 중 구조분해 할당(destructuring-assignment)을 사용하면 

점 연산자를 사용하지 않아도 된다.

 

 

구조분해 할당을 사용하는 방식으로

App.js 를 다음과 같이 수정하고, Food 컴포넌트를 3개 추가하여 여러개의 fav프로퍼티 값을 출력해보겠다.


import React from "react";

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

function App() {
  return (
    <div>
      <h1>헬로</h1>
      <Food fav="kimchi" />
      <Food fav="ramen" />
      <Food fav="samgiopsal" />
      <Food fav="chukumi" />
    </div>
  );
}

export default App;

브라우저에 아래와 같이 출력 ↓


동작 원리

 

 

 

하지만 컴포넌트를 복+붙하는 방식으로는 비효율적이기도하고 웹에서 가져온 데이터를 추가할 수 없다는 단점이 있다.

데이터가 API에서 왔을 경우, 

즉, 서버에서 음식 데이터를 받아 출력하는 경우,

음식 데이터의 개수를 알 수 없기 때문에 컴포넌트의 개수를 정할 수 없게 된다.

 

그렇다면 웹사이트에 동적 데이터를 추가하려면 어떻게 해야 할까.

JavaScript의 map()을 이용할 것.

 

map()함수는 배열의 모든 원소마다 특정 작업을 하는 함수를 적용하고,

그 함수가 반환한 결과를 모아서 배열로 반환해준다.

 

map()함수의 특징에 대해 예시와 함께 공부해보겠다.

 

 

브라우저 콘솔창에

4개의 과일 이름이 저장된 fruits라는 문자열을 선언하고

map함수의 첫 번째 인자로 특정 작업을 하는 함수를 전달해보았더니

fruits의 배열 요소(원소, 엘레멘트)가 차례로 출력된 다음, 배열 [0, 0, 0, 0]이 반환되었다.

 

책에서는 fruits 대신 friends 문자열

 

 

 

map() 함수 특징 

① map()함수의 인자로 전달한 함수는 배열(문자열)의 원소를 대상으로 실행됨.

   (위의 예시에서는 fruits의 원소가 4개 들어있으므로 함수가 4번 실행되었다.)

② 반환된 값이 모여 배열이 되고 ( [0, 0, 0, 0] ), 그 배열이 map()함수의 반환값이 됨.

 

 

위의 특징을 이용해서

fruits.map()의 인자로 과일이름 뒤에 하트를 붙여주는 함수를 전달하면,

각각의 원소(과일이름)에 하트가 추가된 배열을 반환값으로 얻을 수 있다 ↓ 

 

 

위의 내용을 숙지하고 map()함수를 이용해서 App.js 파일의 코드를 수정해보겠다.

(서버에서 데이터가 넘어온다고 가정하고 데이터 입력)


import React from "react";

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

const foodILike = [
  {
    name: 'kimchi',
    image: 'https://img.etoday.co.kr/pto_db/2019/05/600/20190520155753_1330258_1200_1802.jpg',
  },
  {
    name: 'ramen',
    image: 'https://i.ytimg.com/vi/Hf0b_-hVBS4/maxresdefault.jpg',
  },
];

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

export default App;

map함수 적용 원리

 

 

 

브라우저에 아래와 같이 출력 ↓