전 포스트에서 만들었던 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 컴포넌트에서
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 함수는 배열의 각 원소별로 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! 리액트 프로그래밍 정석 / 노마드 코더