[React] 미리 만들어둔 여러 개의 템플릿에 내용물을 동적으로 배분하기

2024. 1. 5. 01:34
반응형

디자이너가 원하는 결과물

 

구현해야하는 조건

- api response로 받아온 책이 몇 권이냐에 따라 carousel 한 페이지에서 렌더링되어야 하는 책의 개수와 순서가 정해져있음

- carousel 1페이지에 들어가는 책은 최소 1권, 최대 5권

- 5권(캐러솔 한페이지당) * 총 4페이지 = 20권까지는 위 템플릿대로 들어가고, 21권째부터 carousel 1번으로 돌아가서 반복(사용자가 등록한 책의 권 수는 무한대로 늘어날 수 있음)

 

 

하나의 템플릿에 데이터를 mapping 하는 것을 넘어, 어떻게 4개의 템플릿에 동적으로 분배해서 렌더링할지 고민했다.

 

 

api 데이터 불러오는 컴포넌트

1. 일단 한 페이지당 5권씩 들어가도록 데이터를 나눠준다.

2. 1번에서 나눠진 데이터를 다시 맵핑하여 한 페이지당 들어갈 정보로 가공한다.

3. 캐러솔 페이지의 props로 넘겨준다.

  // 한 페이지당 5권씩 들어가도록 array 나누기
  const slicedBookList = useMemo((): BookType[][] => {
    const books = data?.data ?? []
    let result = []
    for (let i = 0; i < books.length; i += 5) {
      result.push(books.slice(i, i + 5))
    }
    return result
  }, [data?.data])
  
  
  const pageData = slicedBookList.map((books, index) => {
    return { id: index, pageIndex: index % 4, bookList: books }
  })
  
  
  ...
  
  return (
          <Carousel
          showIndicators={false}
          showArrows={false}
          showStatus={false}
          infiniteLoop={true}
          emulateTouch={true}
        >
          {pageData.map((page) => {
            return (
              <CarouselPage
                key={page.id}
                pageIndex={page.pageIndex}
                bookList={page.bookList}
              />
            )
          })}
        </Carousel>
  )

 

 

CarouselPage.tsx

1. 미리 퍼블리싱해둔 템플릿들을 2차원 배열에 담아주고

2. pageIndex(전체 캐러솔 중 몇번째 페이지인지), bookIndex(특정 캐러솔의 몇 번째 책인지)에 따라 렌더링해준다.

  const covers = [
    [Page0Book0, Page0Book1, Page0Book2, Page0Book3, Page0Book4],
    [Page1Book0, Page1Book1, Page1Book2, Page1Book3, Page1Book4],
    [Page2Book0, Page2Book1, Page2Book2, Page2Book3, Page2Book4],
    [Page3Book0, Page3Book1, Page3Book2, Page3Book3, Page3Book4],
  ]
  
  ...
  
  return(
          <div>
          {bookList.map((book, bookIndex) => {
            // 내용물이 어느 템플릿과 어느 위치에 들어갈지 유동적으로 정해주기
            const Templete = covers[pageIndex][bookIndex]
            return (
              <Templete key={bookIndex} onClick={() => handleSelectBook(book)}>
                <Typo>{book.title}</Typo>
              </Templete>
            )
          })}
        </div>
  )
반응형

BELATED ARTICLES

more