[영화 웹 서비스 만들기] #2 JSX & PROPS ( Component, forEach(), filter(), map() )
본 포스팅은 리액트 JS를 다루고 있습니다.
# 2.0 Creating your first React Component
Localhost
Localhost를 게속 유지하고 창을 계속 띄운 상태로 실행시키고 싶다면 npm start 를 하고 console을 종료하지 않아야 한다. x를 눌러서 숨기는 경우는 계속 작동한다. console만 종료시키지 않으면 된다.
JSX (1)
JS와 HTML의 조합을 JSX라고 한다. React에서 나온 거의 유일한 개념이다.
위의 <APP />는 HTML이 아니다. 아래의 return 안에 있는 내용들은 HTML이다.
Component
위의 <APP /> 과 같은 것들을 Component라고 한다. react는 component와 함께 동작한다. component를 만들고 보기좋게 만들며 component가 data를 보여주게 할 것이다. component는 HTML을 반환하는 함수이다.
<APP /> 부분은 우리가 component를 사용하고자 할 때의 형태이다. App ← 이런 형태로 적으면 react가 알아들을 수 없다.
Component 만들기
- src폴더 안에 (만들고 싶은 component의 이름).js를 생성한다.
- component를 작성할 때마다 import React from "react";를 써줘야 한다. (만약 하지 않으면 react는 여기에 JSX가 있는 component를 사용하는 것을 이해하지 못한다.)
- 파일이름으로 함수를 만든다. (대문자로 파일명 시작했으면 앞글자 대문자로 함수를 만든다.)
- export한다. 코드는 export default 함수이름; .
Component 생성 및 사용 예제 코드
//Potato.js
import React from "react";
function Potato(){
return <h3>I love Potato!!</h3>;
}
export default Potato;
//index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import Potato from "./Potato";
ReactDOM.render(<App /><Potato />, document.getElementById("root"));
위의 코드에서 import를 할 때 "./파일명"를 사용했는데, 여기서 .의 의미는 작성하고 있는 현재 파일과 같은 directory에 있을 때를 말한다.
현재 쓰고 있는 파일이 App.js라 가정해보자. 만약 App.js에 index.js나 Potato.js를 import 하고 싶다면 이 파일은 모두 App.js와 같은 위치 (모두 src 파일안에 위치하고 서로 상하 문서 관계에 있지 않다. )에 있으므로 이럴 때 "./파일명"을 통해 파일을 불러올 수 있다.
주의사항
위의 예제코드에서 ReactDom.render(<App /><Potato />, document.getElementById("root"));처럼 component를 두 개이상 사용할 수 없다. 만약 사용하면 아래와 같은 failed to compile이 뜬다.
따라서 이러한 문제를 해결하기 위해서는 <Potato />를 <App /> 옆에 두는 대신에 App 안에 넣어야 한다. 이럴 경우 사용하고자 하는 component는 App에서만 import 해주면 된다.
맞는 코드
// index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
// App.js
import React from "react";
import Potato from "./Potato";
function App() {
return (
<div>
<h1>hello!!</h1>
<Potato />
</div>
);
}
export default App;
// Potato.js
import React from "react";
function Potato(){
return <h3>I love Potato!!</h3>;
}
export default Potato;
#2.1 Reusable Components with JSX + Props
파일 생성 없이 component 생성 및 사용
import React from "react";
function Potato(){
return <h1>I like potato</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Potato />
</div>
);
}
export default App;
위와 같이 component를 JS에서 함수를 추가하는 것처럼 같은 파일에 정의를 한 뒤 App component에 추가해주면 굳이 파일을 새로 만들지 않아도 만들고 사용할 수 있다.
JSX (2)
정보 전달 (Component에 정보를 보낼 수 있다.)
react는 재사용 가능한 component를 만들어 계속 반복해서 사용할 수 있다. 따라서 아래와 같이 할 필요가 없어진다.
import React from "react";
function Movie(){
return <h1>I like potato</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Movie />
<Movie />
<Movie />
<Movie />
<Movie />
</div>
);
}
export default App;
이렇게 복사 붙여 넣기를 반복할 필요가 없다.
Component 간에 정보를 주고 받기 위해 마치 HTML처럼 어떤 것의 속성에 값을 주는 형식으로 쓴다. 예시는 아래 코드와 같다.
import React from "react";
function Food(){
return <h1>I like potato</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Food fav="kimchi"/>
</div>
);
}
export default App;
Food Component에 kimchi라는 value로 prop(=property) fav을 줬다.
넘기는 정보는 위 처럼 "kimchi"라는 string 뿐만 아니라 something={true}처럼 boolean값을 넘길 수도 있고 papapa={["hello", 1,2,3,4, true]} 처럼 array를 넘길 수도 있다. 이러한 방식으로 father component에서 children component로 원하는 많은 속성(property)를 보낼 수 있다.
누군가가 food component로 정보를 보내려고 하면 (<Food fav="kimchi" />를 쓰면) react는 이 속성을 가져와 food function component의 argument(인자)로 넣게 될 것이다.
import React from "react";
function Food(prop){
console.log(prop);
return <h1>I like potato</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Food name="kimchi" something={true} papapa={["hello",1,2,3, true ]} />
</div>
);
}
export default App;
위 처럼 object로 해당 속성(prop)을 받는다.
function Food(prop){
console.log(prop.fav);
return <h1>I like potato</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Food fav="kimchi" />
</div>
);
}
위와 같이 속성이 하나라도 prop이라는 object를 받고 그 안에 fav가 있는 것이므로 prop.fav라고 써야 해당 내용이 출력된다. 만약 바로 fav를 쓰고 싶다면 {fav}와 같이 {}을 이용하고 그 안에 property의 이름을 쓰면 된다.
import React from "react";
function Food({fav}){
console.log({fav});
return <h1>I like potato</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Food fav="kimchi" />
</div>
);
}
export default App;
{}안에 속성의 이름을 쓰지 않고 다른 것을 쓰게 된다면 그 속성은 정의 되지 않았으므로 undefined라고 뜬다. 따라서 속성의 이름과 함수에서 인자로 받는 부분은 이름이 서로 같아야 한다.
예제
import React from "react";
function Food({ fav }){
return <h1>I like { fav }</h1>;
}
function App() {
return (
<div>
<h1>hello!!</h1>
<Food fav="kimchi" />
</div>
);
}
export default App;
실행결과
이렇게 { fav }를 html요소 안에 넣어 활용할 수 있다.
#2.2 Dynamic Component Generation
동적인 데이터를 추가하는 방법
데이터를 object 형식으로 만들고 이를 모두 모아 배열로 저장한다. map을 써서 배열의 각 item 당 component 함수를 실행하도록 한다.
component 함수 안에서 return 안에 html요소들을 주로 쓰게 되는데 여기서 JS를 쓰고 싶다면 {}를 쓰고 그 안에 사용하면 된다.
👇🏻 [ JS 쓸 때 {}를 쓴다. → 예시코드 더보기 ]
function App() {
return (
<div>
{console.log(foodILike.map(renderFood))}
{foodILike.map(renderFood)}
</div>
);
}
실행 결과는 아래와 같이 React component가 들어있는 배열이 나온다.

import React from "react";
function Food({ name }) {
return <h1>I like { name }</h1>;
}
const foodILike = [
{
name: "Kimchi",
image:
"http://aeriskitchen.com/wp-content/uploads/2008/09/kimchi_bokkeumbap_02-.jpg",
},
{
name: "Samgyeopsal",
image:
"https://3.bp.blogspot.com/-hKwIBxIVcQw/WfsewX3fhJI/AAAAAAAAALk/yHxnxFXcfx4ZKSfHS_RQNKjw3bAC03AnACLcBGAs/s400/DSC07624.jpg",
},
{
name: "Bibimbap",
image:
"http://cdn-image.myrecipes.com/sites/default/files/styles/4_3_horizontal_-_1200x900/public/image/recipes/ck/12/03/bibimbop-ck-x.jpg?itok=RoXlp6Xb",
},
{
name: "Doncasu",
image:
"https://s3-media3.fl.yelpcdn.com/bphoto/7F9eTTQ_yxaWIRytAu5feA/ls.jpg",
},
{
name: "Kimbap",
image:
"http://cdn2.koreanbapsang.com/wp-content/uploads/2012/05/DSC_1238r-e1454170512295.jpg",
},
];
function App() {
return (
<div>
<h1>Hello!!</h1>
{foodILike.map(dish => <Food name = {dish.name}/>)}
</div>
);
}
export default App;
위의 코드를 예시를 들어 설명하면 foodILike이라는 배열을 만들고 데이터를 저장한다. 전체 틀이 되는 App component 함수의 return에서 foodILike을 map 함수를 사용해서 각 item을 object 형식으로 불러온다. 그 다음 Food component를 작성해서 해당 내용이 Food component 함수로 보내지게끔 한다. 보내진 정보는 Food component 함수에서 return 값으로 html 요소를 반환하면서 그 내용이 최종적으로 화면으로 출력된다.
결과
array.map()
map은 인자로 실행시키고자 하는 함수를 주고 array자리에는 /우리가 그 함수를 실행시켜 적용하고자 하는 배열이름을 주면 된다. map은 array의 각 item들에 인자로 준 함수를 실행시키고 그 결과 값을 배열로 만들어 리턴한다.
위의 경우에는 배열의 각 item 별로 console.log를 실행하고 0을 리턴했다. 결과 값은 결국 0이므로 4번의 0이 배열로 만들어 map의 결과 값으로 최종 리턴 되었다. 하지만 원본 friends 배열이 0으로 바뀐건 아니다.
👇🏻 [ 차이점 자세히 보기 ]
forEach()

map()
return 값이 없는 경우


return 값이 없으면 undefined로 실행결과를 내고 이것을 배열로 만들어 map의 반환값으로 최종 return 한다.
return 값이 있는 경우

예제 실행 코드
두 개 이상의 정보 넘기기
import React from "react";
function Food({ name , picture }) {
return (
<div>
<h2>I like {name}</h2>
<img src={picture} />
</div>
);
}
const foodILike = [
{
name: "Kimchi",
image: "http://aeriskitchen.com/wp-content/uploads/2008/09/kimchi_bokkeumbap_02-.jpg"
},
{
name: "Samgyeopsal",
image: "https://3.bp.blogspot.com/-hKwIBxIVcQw/WfsewX3fhJI/AAAAAAAAALk/yHxnxFXcfx4ZKSfHS_RQNKjw3bAC03AnACLcBGAs/s400/DSC07624.jpg"
},
{
name: "Bibimbap",
image: "http://cdn-image.myrecipes.com/sites/default/files/styles/4_3_horizontal_-_1200x900/public/image/recipes/ck/12/03/bibimbop-ck-x.jpg?itok=RoXlp6Xb"
},
{
name: "Doncasu",
image: "https://s3-media3.fl.yelpcdn.com/bphoto/7F9eTTQ_yxaWIRytAu5feA/ls.jpg"
},
{
name: "Kimbap",
image: "http://cdn2.koreanbapsang.com/wp-content/uploads/2012/05/DSC_1238r-e1454170512295.jpg"
}
];
function App() {
return (
<div>
{foodILike.map((dish) => (
<Food name={dish.name} picture= {dish.image} />
))}
</div>
);
}
export default App;
위와 같이 두 개 이상의 정보를 넘기고 싶다면 { name }, { picture }꼴이 아니라 { name, picture } 이렇게 써야 한다.
실행결과
위의 코드에서 인자에 함수를 썼던 것을 밖에 함수로 빼서 쓰면 아래와 같이 코드를 수정할 수 있다.
function renderFood(dish){
return <Food name={dish.name} picture={dish.image} />
}
function App() {
return (
<div>
{foodILike.map(renderFood)}
</div>
);
}