📝

7. 컴포넌트 리스트 만들기

  • 복잡도를 줄이기 위해 새로운 프로젝트로 만들어 진행하겠습니다. 파일은 App.js 하나만을 수정합니다.
    • 💡
      npx create-react-app .
      import './App.css'; function App() { return ( <Hello name="licat"/> ); } function Hello(props) { const name = props.name; return( <div> <h1>안녕, {name} 1호</h1> </div> ) } export default App;
      App.js
 
한 번에 수 많은 데이터가 존재한다면 어떨까요? 만약 10호까지 있다면 아래와 같이 코드를 작성할 수 있습니다. 하지만 이런 방식은 같은 코드를 반복하여 작성해야 합니다.
import './App.css'; function App() { return ( <Hello name="licat"/> ); } function Hello(props) { const name = props.name; return( <div> <h1>안녕, {name} 1호</h1> <h1>안녕, {name} 2호</h1> <h1>안녕, {name} 3호</h1> <h1>안녕, {name} 4호</h1> <h1>안녕, {name} 5호</h1> <h1>안녕, {name} 6호</h1> <h1>안녕, {name} 7호</h1> <h1>안녕, {name} 8호</h1> <h1>안녕, {name} 9호</h1> <h1>안녕, {name} 10호</h1> </div> ) } export default App;
하드코딩한 케이스
 
일단 스타일을 반영하지 않고 단순히 1호에서 10호까지의 결과를 나타낸 컴포넌트 리스트를 만들어 보도록 하겠습니다. map함수를 이용해 봅시다!
💡
map() 메서드는 리스트 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환합니다. [리스트].map((i)=>{return 로직}
import './App.css'; function App() { return ( <Hello name="licat"/> ); } function Hello(props) { const name = props.name; const num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; //1~10호를 만들 것입니다. // list map을 이용하여 h1 태그들의 리스트를 만듭니다. const numComponentsArray = num.map((i)=><h1>안녕, {name} {i}호</h1>); return( <div> {numComponentsArray} </div> ) } export default App;
 
코드를 실행하면 아래와 같이 우리가 원하던 결과를 얻을 수 있습니다.
notion imagenotion image
 
하지만 개발자 도구를 보면 경고가 뜬 모습을 확인할 수 있습니다.
notion imagenotion image
 
"리스트 각 요소가 고유한 key 값을 가지지 않았다."라는 경고 메세지입니다. key 값을 넣어주지 않았기 때문에 에러가 발생한 것입니다. 컴포넌트 안에서 리스트를 렌더링할 때는 꼭 key 값을 넣어줘야 합니다.
key 값은 일반적으로 배열의 id 값을 넣어줍니다. 고유의 값을 찾을 수 없다면 인덱스를 key로 사용하면 되지만 나중에 순서와 관련된 문제가 발생할 수 있기 때문에 권장하지 않습니다.
import './App.css'; function App() { return ( <Hello name="licat"/> ); } function Hello(props) { const name = props.name; const num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; //1~10호를 만들 것입니다. // list map을 이용하여 h1 태그들의 리스트를 만듭니다. const numComponentsArray = num.map((i) => ( <h1 key={i.toString()}> 안녕, {name} {i}호 </h1> )); return( <div> {numComponentsArray} </div> ) } export default App;
 

case 1. 키가 없을 때

만약 여기서 <h2>안녕, 개리 2호</h2> 를 제거한다면 리액트는 어떻게 컴포넌트를 바꿔줄까요?
<h2>안녕, 개리 1호</h2> <h2>안녕, 개리 2호</h2> <h2>안녕, 개리 3호</h2> <h2>안녕, 개리 4호</h2>
 
리액트는 개리 1호부터 4호까지의 트리 요소를 모두 비교한 후, 개리 2호, 개리 3호, 개리 4호 h2태그를 모두 변경하게 될 것 입니다.
<h2>안녕, 개리 1호</h2> <h2>안녕, 개리 3호</h2> <h2>안녕, 개리 4호</h2>
 
'안녕, 개리 2호'를 지우고 '안녕, 개리 3호'를 만듭니다.
'안녕, 개리 3호'를 지우고 '안녕, 개리 4호'를 만듭니다.
'안녕, 개리 4호'를 지웁니다.
 
위 코드에서 변화된 것은 개리 2호가 제거된 것과 개리 3호, 4호의 위치입니다. 하지만 리액트가 느끼기에는 개리 2, 3, 4호가 모두 변경되었다고 생각합니다. 3, 4호가 존재하고 있는데 말이죠. 그래서 2, 3, 4호 h2 태그를 새롭게 그립니다.
 

case 2. 키가 있을 때

<h2 key="1">안녕, 개리 1호</h2> <h2 key="2">안녕, 개리 2호</h2> <h2 key="3">안녕, 개리 3호</h2> <h2 key="4">안녕, 개리 4호</h2>
<h2 key="1">안녕, 개리 1호</h2> <h2 key="3">안녕, 개리 3호</h2> <h2 key="4">안녕, 개리 4호</h2>
 
위와 같이 나열된 요소에서 key 속성을 넣어줬을 때, 리액트는 어떻게 컴포넌트를 바꿔줄까요? 리액트는 key를 통해 기존 트리 요소와 이후 트리 요소들이 일치하는지 확인합니다.
  • key가 2인 요소가 존재하지 않으니, '안녕, 개리 2호'를 지웁니다.
  • key가 3인 요소, key가 4인 요소는 존재하는데 위치만 다른 것을 알고, '안녕, 개리 3호', '안녕, 개리 4호'의 위치를 옮겨줍니다. 지우고 다시 생성하지 않고 말이죠.
 

연습문제

다음과 같은 data가 있다고 하였을 때 아래와 같이 화면을 만들어주세요. props로 전달하지 않고, 컴포넌트 내부에서 변수로 만듭니다.
notion imagenotion image
const productList = { products: [ { title: "개발자 무릎 담요", price: 17500, id: 101, }, { title: "Hack Your Life 개발자 노트북 파우치", price: 29000, id: 102, }, { title: "우당탕탕 라이켓의 실험실 스티커북", price: 29000, id: 103, }, { title: "버그를 Java라 버그잡는 개리씨 키링", price: 29000, id: 104, }, ], };
정답코드
import React from "react"; const Home = () => { const productList = { products: [ { title: "개발자 무릎 담요", price: 17500, id: 101, }, { title: "Hack Your Life 개발자 노트북 파우치", price: 29000, id: 102, }, { title: "우당탕탕 라이켓의 실험실 스티커북", price: 29000, id: 103, }, { title: "버그를 Java라 버그잡는 개리씨 키링", price: 29000, id: 104, }, ], }; return ( <> {productList.products.map((item, idx) => ( <li key={item.id} style={{ listStyle: "none", }} > <h2> {idx + 1} {item.title} </h2> <span>{`${item.price}원`}</span> </li> ))} </> ); }; export default Home;