Booklist(toy)

Jaeseok Han·2023년 9월 19일
0

React Basic

목록 보기
6/30

BookList 컴포넌트 만들어 보기

목적

https://www.amazon.com/Best-Sellers-Books/zgbs/books
아마존 판매 사이트의 책 리스트에 관한 클론코딩을 만든다.

구조

  • BookList(책 목록 컴포넌트)
    • Book(책 컴포넌트)
      - Image, Title, Author (책 내부에 들어갈 컴포넌트)

컴포넌트 생성

import React, { Fragment } from 'react';
import ReactDOM from 'react-dom/client';

const BookList = () => {
    return (
        <section>
            <Book/>
        </section>
    )
}

const Book = () => {
    return <article>
        <Image/>
        <Title/>
        <Author/>
    </article>
}

const Image = () => <h2>이미지 위치</h2>
const Title = () => <h2>제목</h2>
const Author = () => {
    return <h4>저자</h4>
}


const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(<BookList/>)

Book 컴포넌트 재사용

const BookList = () => {
    return (
        <section>
            <Book/>
            <Book/>
            <Book/>
            <Book/>
            <Book/>
        </section>
    )
}

컴포넌트를 생성하고 재사용하게 된다면 불필요한 코드를 줄일 수 있다.

Book 내용 카피하기

내용 넣기

const Image = () => (
    <img src="https://images-na.ssl-images-amazon.com/images/I/61sp+sMfrXL._AC_UL600_SR600,400_.jpg"/>)
const Title = () => <h2>The Democrat Party Hates America</h2>
const Author = () => {
    return <h4>Mark R. Levin</h4>
}

데이터 값이 제대로 보여주는걸 확인 할 수 있다.

CSS 적용하기

create index.css in src

index.css

* {
    margin : 0;
    padding : 0;
    box-sizing: border-box;
}

body{
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    background :#f1f5f8;
    color : #222;
}

css 추가

index.js

import './index.css'

book 스타일 적용


* {
    margin : 0;
    padding : 0;
    box-sizing: border-box;
}

body{
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    background :#f1f5f8;
    color : #222;
}

.booklist {
    width: 90vw;
    max-width: 1170px;
    margin: 5rem auto;
    display: grid;
    gap: 2rem;
}

@media screen and (min-width: 768px) {
    .booklist{
        grid-template-columns: repeat(3,1fr);
    }
}

.book {
    background: #fff;
    border-radius: 1rem;
    padding: 2rem;
    text-align: center;
}

.book img {
    width: 100%;
    object-fit: cover;
}

.book h2 {
    margin-top: 1rem;
    font-size: 1rem;
}

CSS 적용하기

create index.css in src

index.css

* {
    margin : 0;
    padding : 0;
    box-sizing: border-box;
}

body{
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    background :#f1f5f8;
    color : #222;
}

css 추가

index.js

import './index.css'

book 스타일 적용


* {
    margin : 0;
    padding : 0;
    box-sizing: border-box;
}

body{
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    background :#f1f5f8;
    color : #222;
}

.booklist {
    width: 90vw;
    max-width: 1170px;
    margin: 5rem auto;
    display: grid;
    gap: 2rem;
}

@media screen and (min-width: 768px) {
    .booklist{
        grid-template-columns: repeat(3,1fr);
    }
}

.book {
    background: #fff;
    border-radius: 1rem;
    padding: 2rem;
    text-align: center;
}

.book img {
    width: 100%;
    object-fit: cover;
}

.book h2 {
    margin-top: 1rem;
    font-size: 1rem;
}

Images

로컬 이미지 (public 폴더)

이미지 경로

  • 외부 이미지(다른 서버에 이미지를 호스팅) url 필요
  • 로컬 이미지(public 폴더) - 낮은 성능
  • 로컬 이미지(src 폴더) - 더 나은

book이미지 적용

  1. 이미지 다운로드 후 이름 설정(book-1)
  2. public폴더 안에 images폴더를 생성 후 book에 사용할 이미지 넣기
  3. Image 컴포넌트 src 경로에 로컬 이미지 적용
<img src="./images/book-1.jpg"/>

JSX - CSS (inline styles)

style 속성을 사용한다.
JSX에서 {}를 사용한다는 것은 Javascript로 돌아간다는 의미
key는 그냥 value는 ''로 넣는다.

Author css(inline style) 적용

const Author = () => {
    return (
        <h4 style={{color: '#617d98', fontSize: '0.75', marginTop: '0.5rem'}}>
            Mark R. Levin
        </h4>
    )
}

따로 선언한 css 방법

const Author = () => {
    const inlineHeadingStyles = {
        color: '#617d98',
        fontSize: '0.75',
        marginTop: '0.5rem'
    }
    return (
        <h4 style={inlineHeadingStyles}>
            Mark R. Levin
        </h4>
    )
}

css를 리팩토링하여 사용할 수 있다.

JSX - Javascript

변수값 내부에 사용

선언된 변수를 사용하기 위해서는 {}안에 넣어야한다.
{}안에 표현식은 사용할 수 없다.

const Book = () => {
    const title = 'The Democrat Party Hates America'
    return <article className='book'>
        <img src="./images/book-1.jpg"/>
        <h2>{title}</h2>
        <h4>
            Mark R. Levin
        </h4>
    </article>
}

Props

상위 컴포넌트에 선언된 변수를 하위 컴포넌트에 넘겨 사용가능하도록 값을 넘겨받는다.

props 사용해보기

const BookList = () => {
    return (
        <section className="booklist">
            <Book job="developer"/>
            <Book title="random title" number={22}/>
        </section>
    )
}
const Book = (props) => {
    console.log(props);
    return <article className='book'>
        <img src={img}/>
        <h2>{title}</h2>
        <h4>{author}</h4>
    </article>
}

컴포넌트 속성으로 값을 넘기고 props로 받아서 사용이 가능하다.

동적으로 적용해보기

서로 다른 종류의 값을 객체로 설정하여 다른 값을 props로 넘겨줌

const firstBook = {
    author : "Mark R. Levin",
    title : "The Democrat Party Hates America",
    img : "./images/book-1.jpg"
}

const secondBook = {
    author : "Walter Isaacson",
    title : "Elon Musk",
    img : "./images/book-2.jpg"
}

const BookList = () => {
    return (
        <section className="booklist">
            <Book 
                author={firstBook.author}
                title={firstBook.title}
                img={firstBook.img}
            />
             <Book 
                author={secondBook.author}
                title={secondBook.title}
                img={secondBook.img}
            />
        </section>
    )
}

Access Props

props를 효율적으로 접근하기 위해서는 구조분해 할당을 사용하면 좋다.

구조분해 할당

여러 프로퍼티를 사용하기 위해서 변수에 할당할때 사용함.

예시

일반적인 객체에 할당된 값에 접근

const someObject = {
    name : 'jaeseok',
    job : 'developer',
    location : 'seoul'
}
console.log(someObject.name);

구조분해 할당 객체 값 접근

const someObject = {
    name : 'jaeseok',
    job : 'developer',
    location : 'seoul'
}
const { name, job } = someObject;
console.log(name)

props 구조분해 할당

Book 컴포넌트 적용

const Book = (props) => {
    return <article className='book'>
        <img src={props.img} alt={props.title}/>
        <h2>{props.title}</h2>
        <h4>{props.author}</h4>
    </article>
}

사용예시1

const Book = (props) => {
    const {img, title, author} = props;
    return <article className='book'>
        <img src={img} alt={title}/>
        <h2>{title}</h2>
        <h4>{author}</h4>
    </article>
}

props 라는 객체명을 한번만 참조하여 사용하므로 코드중복성을 제거하고 간결해진다.

사용예시2

const Book = ({img, title, author}) => {
    return <article className='book'>
    <img src={img} alt={title}/>
    <h2>{title}</h2>
    <h4>{author}</h4>
    </article>
}

함수 파라미터 내부에서 구조 분해 할당을 해주는 방법도 가능하다.

Children prop

하위 컴포넌트로 선택적인 태그를 넘겨주는건 내부에 넣어서 하면 되지않은다

<Book 
  author={firstBook.author}
  title={firstBook.title}
  img={firstBook.img}
  >
  <p>텍스트</p>
  <button>버튼</button>
</Book>

p태그는 렌더링 되지않음

children

내부로 넘긴 태그는는 props객체의 children으로 넘겨준다.

예시

const Book = ({img, title, author, children}) => {
    return <article className='book'>
      {children}
    <img src={img} alt={title}/>
    <h2>{title}</h2>
    <h4>{author}</h4>
    </article>
}

or

const Book = (props) => {
    const {img, title, author} = props;
    return <article className='book'>
      	{children}
        <img src={img} alt={title}/>
        <h2>{title}</h2>
        <h4>{author}</h4>
    </article>
}

Simple List

순차적인 배열을 처리하기 위한 간단한 방법

map

배열을 순회하여 콜백함수를 실행시킴

const books = [
    {
        author : "Mark R. Levin",
        title : "The Democrat Party Hates America",
        img : "./images/book-1.jpg"
    },
    {
        author : "Walter Isaacson",
        title : "Elon Musk",
        img : "./images/book-2.jpg"
    }
]

const newNames = names.map((name) => {
    console.log(name)
})

💡 map의 콜백함수 파라미터(name)는 임의로 설정하는 변수

순차적으로 콜백함수가 실행되는 것을 알 수 있다.

렌더링

const names = ['john' , 'peter', 'susan'];
  
const BookList = () => {
    return (
        <section className="booklist">
            {names.map((name) => {
                return <h1>{name}</h1>
            })}
        </section>
    )
}

배열의 내용을 잘 순회하여 렌더링이 되는 것을 알 수 있다.

Proper List

books 리스트 내용 레더링

const books = [
    {
        author : "Mark R. Levin",
        title : "The Democrat Party Hates America",
        img : "./images/book-1.jpg"
    },
    {
        author : "Walter Isaacson",
        title : "Elon Musk",
        img : "./images/book-2.jpg"
    }
]

  
const BookList = () => {
    return (
        <section className="booklist">
            {books.map((book) => {
                console.log(book)
                return (
                    <div>
                        <h2>{book.author}</h2>
                    </div>
                )
            })}
        </section>
    )
}

Book 컴포넌트 활용

const BookList = () => {
    return (
        <section className="booklist">
            {books.map((book) => {
                const {img, title, author} = book;
                return (
                    <Book img={img} title={title} author={author}></Book>
                )
            })}
        </section>
    )
}


const Book = (props) => {
    const {img, title, author} = props;
    return <article className='book'>
        <img src={img} alt={title}/>
        <h2>{title}</h2>
        <h4>{author}</h4>
    </article>
}

BookList 에서 books의 내용을 구조 분해 할당하여 Book 컴포넌트에서 활용

Key Prop

key 오류

💡map을 사용할 대는 key값을 넣어주어야 한다.
(보통은 id(인덱스)값을 넣어준다.)

Props - Options

Spread Operation

const BookList = () => {
    return (
        <section className="booklist">
            {books.map((book) => {
                return (
                    <Book {...book} key={book.id}></Book>
                )
            })}
        </section>
    )
}



const Book = (props) => {
    const {img, title, author} = props;
    return <article className='book'>
        <img src={img} alt={title}/>
        <h2>{title}</h2>
        <h4>{author}</h4>
    </article>
}

0개의 댓글