React 실습: 책 목록 및 상세 정보 웹사이트
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를 활용하여 부모-자식 컴포넌트 간에 데이터를 전달하고,
각 컴포넌트가 맡은 역할에 맞게 화면을 구성하는 방식으로 컴포넌트 기반 설계 실습!!!!