index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,document.getElementById('root')
);
ReactDom.render 안의 <App />은 컴포넌트이다. 리액트는 컴포넌트를 사용해서 HTML처럼 사용할 때 필요하다. Javascript와 HTML의 이러한 조합을 jsx라고 부른다.
그렇다면 컴포넌트를 만드는 방법은 무엇일까?
src 하위에 Potato.js에 아래와 같이 작성해보자.
import React from 'react';
function Potato(){
return <h3>I love potato.</h3>
}
jsx를 하기위해선 항상 리액트가 import 되어있어야한다. 그리고 함수 이름의 첫번째 글자는 항상 대문자여야한다.
그리고 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')
);
하지만 이러면 작동하지않는다.
react app은 하나의 컴포넌트만 rendering할 수 있기 때문이다. 이를 사용하기 위해 App.js안에서 사용해보자.
import React from 'react';
import Potato from './Potato';
function App() {
return (
<div>
<h1>Hello!</h1>
<Potato />
</div>
);
}
export default App;
Potato.js를 지우고 App.js안으로 옮기자.
import React from 'react';
function Potato(){
return <h3>I like Potato.</h3>
}
function App() {
return (
<div>
<h1>Hello!</h1>
<Potato />
</div>
);
}
export default App;
코드 분리가 필요하다면 위와같이 파일을 분할해서 이용하고, 그렇지 않다면 이렇게 사용하자.
리액트에서는 컴포넌트가 재사용이 가능하다.
컴포넌트는 속성을 부여받을 수 있는데 예를들어서 아래와 같이 작성한다면, Food 컴포넌트에 fav라는 property에 kimchi라는 value를 준 것이다. 여러가지의 속성을 줄수도있다.
import React from 'react';
function Food(props){
return <h3>I like Potato.</h3>
}
function App() {
return (
<div>
<h1>Hello!</h1>
<Food fav="kimchi" />
</div>
);
}
export default App;
주어진 속성의 value만 가지고 올수도 있다.
function Food(props.fav)
function Food({ fav })
이를 응용하면 아래와 같이 작성할 수 있다.
import React from 'react';
function Food({ fav }){
return <h3>I like { fav }.</h3>
}
function App() {
return (
<div>
<h1>Hello!</h1>
<Food fav="kimchi" />
<Food fav="ramen" />
<Food fav="potato" />
</div>
);
}
export default App;
위 코드는 좋지 못한 코드이다 왜냐면 반복적인 작업을 일일이 해야하니까..?
이를 해결하기 위한 방법을 알아보자.
예를들어 특정 API가 주어진다고 쳐보자.
javascript의 map을 이용하여 처리를 하면된다.
import React from 'react';
function Food({name, picture}){
return <div>
<h2>I like {name}</h2>
<img src = {picture} />
</div>
}
const foodILike = [
{
name: "Kimchi",
image:"https://okonomikitchen.com/wp-content/uploads/2020/03/vegan-kimchi-recipe-12-of-14.jpg"
},
{
name: "Ramen",
image:"https://hips.hearstapps.com/hmg-prod/images/190208-delish-ramen-horizontal-093-1550096715.jpg"
},
{
name: "Potato",
image:"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/delish-191907-twice-baked-potatoes-0027-landscape-pf-1564166855.png?crop=0.668xw:1.00xh;0.289xw,0&resize=480:*"
},
]
function App() {
return (
<div>
<h1>Hello!</h1>
{ foodILike.map(dish => <Food name={dish.name} picture={dish.image} />)}
</div>
);
}
export default App;
잘 작동하지만, key값이 없다는 에러가 뜬다. 이를 해결해주기위해 배열에 id를 부여하자.
그리고, img값에 alt를 추가하자.
import React from 'react';
function Food({name, picture}){
return <div>
<h2>I like {name}</h2>
<img src={picture} alt={name} />
</div>
}
const foodILike = [
{
id:"1",
name: "Kimchi",
image:"https://okonomikitchen.com/wp-content/uploads/2020/03/vegan-kimchi-recipe-12-of-14.jpg"
},
{
id:"2",
name: "Ramen",
image:"https://hips.hearstapps.com/hmg-prod/images/190208-delish-ramen-horizontal-093-1550096715.jpg"
},
{
id:"3",
name: "Potato",
image:"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/delish-191907-twice-baked-potatoes-0027-landscape-pf-1564166855.png?crop=0.668xw:1.00xh;0.289xw,0&resize=480:*"
},
]
function App() {
return (
<div>
<h1>Hello!</h1>
{ foodILike.map(dish => <Food key={dish.id} name={dish.name} picture={dish.image} />)}
</div>
);
}
export default App;
아무런 경고, 에러 없이 잘 작성되었다.
부모 컴포넌트에서 받은 props가 내가 예상한 props인지 확인할 필요가 있다.
우선 리스트 안에 rating을 추가하고, npm i prop-types를 입력하여 설치하자.
import React from 'react';
import PropTypes from "prop-types";
function Food({name, picture, rating}){
return <div>
<h2>I like {name}</h2>
<h4>{rating}/5.0</h4>
<img src={picture} alt={name} />
</div>
}
Food.propTypes = {
name : PropTypes.string.isRequired,
picture : PropTypes.string.isRequired,
rating : PropTypes.number.isRequired
}
const foodILike = [
{
id:"1",
name: "Kimchi",
image:"https://okonomikitchen.com/wp-content/uploads/2020/03/vegan-kimchi-recipe-12-of-14.jpg",
rating: 5
},
{
id:"2",
name: "Ramen",
image:"https://hips.hearstapps.com/hmg-prod/images/190208-delish-ramen-horizontal-093-1550096715.jpg",
rating: 4.9
},
{
id:"3",
name: "Potato",
image:"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/delish-191907-twice-baked-potatoes-0027-landscape-pf-1564166855.png?crop=0.668xw:1.00xh;0.289xw,0&resize=480:*",
rating: 4.8
},
]
function App() {
return (
<div>
<h1>Hello!</h1>
{ foodILike.map(dish => <Food
key={dish.id}
name={dish.name}
picture={dish.image}
rating={dish.rating}
/>)}
</div>
);
}
export default App;