[React] 컴포넌트 반복하기

youngseo·2022년 7월 27일
0

REACT

목록 보기
17/52
post-thumbnail

리스트와 key / 폼과 이벤트 제어하기

react 공식문서

컴포넌트 반복하기

위와 같은 네이버 웹툰 페이지에서는 카드를 컴포넌트로 만들어 활용할 수 있습니다.

그런데 이를 렌더링하는 경우

export default function PreveiwCardParent(){
  return (
  <>
     <PreveiwCard imgSrc={""} title={""} subtitle={""} author={""}>
     <PreveiwCard imgSrc={""} title={""} subtitle={""} author={""}>
     <PreveiwCard imgSrc={""} title={""} subtitle={""} author={""}> 
     <PreveiwCard imgSrc={""} title={""} subtitle={""} author={""}>
     <PreveiwCard imgSrc={""} title={""} subtitle={""} author={""}>
     <PreveiwCard imgSrc={""} title={""} subtitle={""} author={""}>
   </>
  )
}

위와 같이 각각의 컴포넌트에 하나씩 데이터를 넘겨주는 것은 너무 비효율적입니다. 이 때 Array.prototype.map을 활용하면 보다 효율적으로 코드를 작성 할 수 있습니다.

return (
  <>
    {cardInfo.map(info => ({
     <PreveiwCard 
       imgSrc={info.imgSrc} 
       title={info.title} 
       subtitle={info.subtitle} 
       author={info.author}
     />
    }))}
 </>
  )

그런데 화면에는 잘 렌더링이 되지만, 콘솔창에 에러가 뜨는 것을 확인할 수 있습니다. Key는 엘레멘트에 안정적인 고유성을 부여하기 위해 사용하며 props를 넘길 때 배열 내부의 엘리먼트를 key로 지정해줘야합니다.

const listItems = number.map((list)=>
  <li key={list.id} >
    {list.text}   
  </li>
)

또한 key는 해당항목을 고유하게 식별할 수 있는 문자열을 사용하는 것이 좋습니다.

key가 왜필요할까?

  • 리액트에서는 DOM을 효율적으로 업데이트하기 위해 setState를 할 때 비동기적으로 동작하고, 연속적으로 setState를 호출했을 때 배치처리를 하게 됩니다.
  • 만약 map을 사용하는 경우 리액트에서는 컴포넌트가 리렌더링 될 때마다 map을 돌며, 이전에 렌더링 된 요소들과 비교하며 어떤 요소가 변경되었는지 파악하게 됩니다.

예제

만약, 랜덤하게 뽑은 카드 배열을 자식 컴포넌트에서 하나씩 호출하고 싶은 경우 어떻게 해야할까?

3-1 나의 답안

import './App.css';
import React, {useState, useEffect} from 'react';
import BusinessCard from './components/BusinessCard';
import datas from './components/card'

function App() {
  const [cards, setCards] = useState([])
  const [selectcards, setSelectCards] = useState([])

    //componentDidmount와 같이 동작
    useEffect(() => {
      setCards(datas)
    }, [])

  //random함수
  function draw() {
    //조건추가
    if(selectcards.length > 2) {
      const names = selectcards.reduce((acc, cur) => {
        return acc = acc.concat(`${cur.name}, `)
      }, "")

      return  alert(`당첨자는 ${names} 입니다.`)
  
    }


    const randomIdx = Math.floor(Math.random() * cards.length)
    const randomItem = cards[randomIdx]

    setCards(cards.filter(card => card.phoneNumber !== randomItem.phoneNumber))
    setSelectCards([...selectcards, randomItem])
  }

  return (
    <div>
      {cards.length > 0 && <button onClick={draw}>추첨하기</button>}
      {selectcards.length>0 && <BusinessCard selectcards={selectcards} key={selectcards.phoneNumber} />}
    </div>
  )
}

export default App;
import React from 'react'

function BusinessCard({selectcards}) {
  return (
    <>
      {selectcards.map(card => {
        return (
         <div>
          <div>회사: {card.company}</div>
          <div>: {card.team}</div>
          <div>이름: {card.name}</div>
          <div>휴대번호: {card.phoneNumber}</div>
          <div>이메일: {card.email}</div>

         </div>
        )
      })}
    </>
  )
}

export default BusinessCard

3-2 모범답안

  return (
    <div>
      { cards.length > 0 && <button onClick={draw}>추첨하기</button> }
      {/* {pickedCards.length > 0 && (
        <BusinessCard info={pickedCards[pickedCards.length-1]}/>
      )} */}
      {pickedCards.length > 0 && pickedCards.map(pickedCard => <BusinessCard info={pickedCard} key={pickedCard.phoneNumber} />)}
    </div>

3-3 모범답안2

변수로 뺼수도 있습니다.

  const result = pickedCards.map(pickedCard => <BusinessCard info={pickedCard} key={pickedCard.phoneNumber} />)


  return (
    <div>
      { cards.length > 0 && <button onClick={draw}>추첨하기</button> }
      {/* {pickedCards.length > 0 && (
        <BusinessCard info={pickedCards[pickedCards.length-1]}/>
      )} */}
      {pickedCards.length > 0 && result }
    </div>
  );
}

0개의 댓글