React

React 실습: 책 목록 및 상세 정보 웹사이트

startfront 2025. 4. 4. 17:39

React 실습

컴포넌트의 역할을분리하고 props와 state 상태관리를 활용하여

다양한 책 정보를 목록으로 보여주고, 각 책을 클릭하면 책의 상세 정보를 표시하는 웹사이트 만들어 보기!!!!

 

- 구조

Books(책 정보)->
app->bookDetail
app-> booklist->bookitem

 

BookItem은 책 정보를 렌더링
BookList는 여러 BookItem을 렌더링
BookDetail은 선택된 책의 세부 정보를 표시

 

 

  • BookItem: 각 책에 대한 정보를 테이블 행(tr)에 출력 / 버튼을 클릭하면 bookSelect 함수가 호출 부모 컴포넌트로 선택된 책 정보를 전달
  • BookList: 책 목록을 테이블 형식으로 출력 /  각 책 항목은 BookItem을 사용하여 렌더링
  • BookDetail: 선택된 책에 대한 상세 정보를 카드 형식으로 표시

 

Books.js

책들의 정보를 담고 있는 배열

각 책은 객체 형식으로 되어 있으며, isbn, title, author, price, img, describ 같은 속성을 갖고 있음

-> App 컴포넌트에서 사용되고, 책 목록을 표시

const Books = [
  {
    isbn: "9781617293986",  // 책의 고유 ISBN 코드
    title: "Spring Microservices in Action",  // 책 제목
    author: "John Carnell",  // 책 저자
    price: 59.92,  // 책 가격
    img: "spring.jpg",  // 책 이미지 파일 이름
    describ: "Spring Boot and Spring Cloud offer Java developers an easy ..."  // 책 설명
  },
  {
    isbn: "9781491954621",
    title: "Learning React",
    author: "Alex Banks , Eve Porcello",
    price: 49.19,
    img: "react.jpg",
    describ: "Interested in React but find yourself confused ...",
  },
 //.....중간 생략
];

export default Books;

 

App.js

책 목록선택된 책을 별도의 상태로 관리하기 위해 useState 두번 사용

const [books] = useState(Books); 
// `Books`에서 가져온 책 목록을 `books` 상태에 저장

=>  Books는 처음에 Books.js 파일에서 정의된 고정된 책 목록으로

      books는 고정된 데이터 /그래서 따로 setBooks를 쓰지 않았

const [book, setBook] = useState(Books[0]);
// 기본으로 첫 번째 책을 선택하여 `book` 상태에 저장

=> book은 사용자가 선택한 책을 반영하며

     사용자가 책 목록에서 책을 선택할 때마다 업데이트!!!!!!

 

book은 props로 bookDetail에 전달

books , bookSelect props 로 bookList 전달

 

- App.js  코드 확인

import { useState } from "react";
import "./App.css";
import Books from "./Books"; // 책 목록을 저장한 데이터
import BookList from "./component/BookList"; // 책 목록을 보여주는 컴포넌트
import BookDetail from "./component/BookDetail"; // 선택된 책의 상세 정보를 보여주는 컴포넌트

function App() {
  // Books에서 책 목록을 가져와 books 상태로 저장
  const [books] = useState(Books); 
  // 기본으로 첫 번째 책을 선택하여 book 상태로 저장
  const [book, setBook] = useState(Books[0]);

  return (
    <div className="container">
      {/* 선택된 책의 상세 정보를 BookDetail 컴포넌트로 전달 */}
      <BookDetail book={book} />
      {/* 책 목록을 BookList 컴포넌트로 전달 */}
      <BookList
        books={books} // 책 목록을 전달
        bookSelect={(selectBook) => {
          // 책을 선택하면 book 상태를 업데이트
          setBook(selectBook);
        }}
      />
    </div>
  );
}

export default App;

 

부모에 state 지정 후 props 로 자식에 활용!!!

BookList.js

: 책 목록을 화면에 랜더링

  books를 받아 => map으로 순회하여 Bookitem으로 전달

map 함수
: 자바스크립트 배열의 내장 함수로, 반복되는 컴포넌트를 렌더링하기 위해 사용
import React from "react";
import "../styles/BookList.css";
import BookItem from "./BookItem";

// BookList는 책 목록을 화면에 렌더링
// props로 전달된 books(책 목록)를 받아서 각 책을 BookItem 컴포넌트로 전달합니다.
const BookList = ({ books, bookSelect }) => {
  return (
    // 테이블 형태로 책 목록을 출력
    <table className="book-table">
      <thead>
        <tr className="book-header">
          {/* 테이블의 헤더 */}
          <th>이미지</th>
          <th>제목</th>
          <th>가격</th>
          <th>저자</th>
          <th>비고</th>
        </tr>
      </thead>

      <tbody>
        {/* books 배열을 순회하며 각 책을 BookItem 컴포넌트에 전달 */}
        {books.map((bookItem) => (
          // 각 책을 BookItem으로 전달하며 고유의 key로 isbn 사용
          <BookItem key={bookItem.isbn} bookItem={bookItem} bookSelect={bookSelect} />
        ))}
      </tbody>
    </table>
  );
};

export default BookList;

 

BookItem.js

: 책 하나의  정보를 화면에 표시하는 역할

 => props로 전달된 bookItem(books배열을 순회한 각 책 정보) 을 사용하여 책의 정보를 렌더링

import React from "react";
import "../styles/BookItem.css";

const BookItem = ({ bookItem, bookSelect }) => {
  return (
    // <tr>책의 정보를 테이블 형식으로 표시
    <tr className="book-row">
      <td>
        <img
          className="book-thumbnail"
          // bookItem에서 img 파일명을 가져와 해당 이미지를 표시
          src={require(`../assets/images/${bookItem.img}`)}
          alt={bookItem.title} 
        />
      </td>

      <td>{bookItem.title}</td>
      <td>{bookItem.price}</td>
      <td>{bookItem.author}</td>
      <td>
        {/* 선택 버튼 클릭 시 bookSelect 함수 호출하여 해당 책을 선택 */}
        <button
          className="select-button"
          onClick={() => {
            bookSelect(bookItem); // 선택된 책을 부모 컴포넌트에 전달
          }}
        >
          선택
        </button>
      </td>
    </tr>
  );
};

export default BookItem;

 

=>

select-button 버튼을 클릭하면

bookSelect 함수가 실행되고,

이 함수는 부모 컴포넌트인 App에서 전달된 함수로, 해당 책을 App의 book 상태로 설정

BookDetail.js

: BookDetail 컴포넌트는 선택된 책의 상세 정보를 보여주는 역할
  =>props로 전달된 book을 사용하여 상세 정보를 렌더링

import React from 'react';
import '../styles/BookDetail.css';

const BookDetail = ({ book }) => {
  return (
    <div className='book-card'>
      <img 
        src={require(`../assets/images/${book.img}`)} // book에서 img 경로를 가져와서 이미지 표시
        alt={book.title} // 책 제목을 alt로 설정
        className='book-image'
      />
      
      <div className='book-info'>
        <h2 className='book-title'>{book.title}</h2>
        <h4 className='book-author'>{book.author}</h4>
        <h4 className='book-price'>{book.price}</h4>
      </div>         
    </div>
  );
};

export default BookDetail;

 

=>

book은 App에서 전달된 prop이므로,

이 컴포넌트는 부모의 상태를 기반으로 선택된 책을 보여준다.

 

* 각 css파일 생략

- 결과

 

 

props와 state를 활용하여 부모-자식 컴포넌트 간에 데이터를 전달하고,
각 컴포넌트가 맡은 역할에 맞게 화면을 구성하는 방식으로 컴포넌트 기반 설계 실습!!!!