본문 바로가기

프로그래밍&IT/React & CSS

Coding Apple, React 강좌 내용 정리.15 - Component in Component , build 명령어

React ??

Component in Component

어쩔수없이 저번까지 진행한 소스 내용

(App.js 지금까지)

import './App.css';
import React, {useState} from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import {Button, Container,Navbar, Nav, NavDropdown, Card} from 'react-bootstrap'
import {Route, Link, Switch} from 'react-router-dom'
import {} from 'react-bootstrap'
import Data from './data.js'
import Detail from './Detail';
import axios from 'axios'

function App() {
  let [shoes, shoes변경] = useState(Data)  

  return (
    <div className="App">
      <Navbar bg="light" expand="lg">
        <Container>
          <Navbar.Brand href="#home">Shoe Shop</Navbar.Brand>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="me-auto">
              <Nav.Link><Link to="/">Home</Link></Nav.Link>
              <Nav.Link><Link to="/detail">Detail</Link></Nav.Link>
              <NavDropdown title="Dropdown" id="basic-nav-dropdown">
                <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
                <NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item>
                <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
                <NavDropdown.Divider />
                <NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item>
              </NavDropdown>
            </Nav>
          </Navbar.Collapse>
        </Container>
      </Navbar>

      <Switch>
        {/* 상위 페이지 */}
        <Route exact path="/">
          <Card style={{ width: '100%' }}>
            {/* <Card.Img variant="top" src="holder.js/100px180" /> */}
            <Card.Body>
              <Card.Title>Welcome!</Card.Title>
              <Card.Text>
                Some quick example text to build on the card title and make up the bulk of
                the card's content.
              </Card.Text>
              <Button variant="primary">Go somewhere</Button>
            </Card.Body>
          </Card>

          <div className="container">
            <div className="row">
            {
              shoes.map( (shoe, idx)=> {
                return <Goods shoes={shoe} key={idx} />
              })
            }
            </div>
            <button className="btn btn-primary" onClick={
              ()=> {
                // 로딩 중 표시 할수도
                axios.get('https://codingapple1.github.io/shop/data2.json')
                // ajax의 결과를 result에 담아둔다.
                .then( (result)=> {
                  // ajax로 받아온 결과물을 추가
                  // 복사본만들기위해, ... 사용, 대괄호를 벗겨라?

                  // 로딩 중 표시 없애기
                  shoes변경( [...shoes, ...result.data ] );
                })
                .catch( ()=> {
                  console.log("Failed");
                })
              }}>더 보기</button>
          </div>
        </Route>

        <Route path="/detail/:id">
          <Detail shoes={shoes} />
        </Route>
        
        {/* /:
          '/모든문자' 라는 경로를 의미 
          여러개가 
        */}
        <Route path="/:id">
          <div>무조건 보이기</div>
        </Route>
      </Switch>      
    </div>
  );
}

function Goods(props) {
  return (
    <div className="col-md-4">
          <img src={"https://codingapple1.github.io/shop/shoes"+props.shoes.id +".jpg"} width="100%" />
          <h4>{props.shoes.title}</h4>
          <p>{props.shoes.price}</p>
    </div>
  )
}

export default App;

 

상품 재고 표시

- 일단 재고량은 테스트 데이터를 state로 만들어보기

let [재고, 재고변경] = useState( [10,11,12] );

- 되도록 중요하게 처리할 데이터는 상위 component에 놓는다

 

이 데이터를 Detail까지 데이터바인딩 할 것이다.

(Detail.js 여기까지)

import React, {useState, useEffect } from "react"
import {useHistory} from 'react-router-dom'
import {useParams} from 'react-router-dom'
import styled from 'styled-components'
import './Detail.scss'

function Detail(props) {
      // `글자 ${변수명}글자`
    let hist = useHistory(); // react-router-dom ver5 이상, 방문기록 등을 저장해놓은 object라 이해
    let {id} = useParams(); //사용자가 입력한 URL 파라미터들, /:id 자리에 입력된 값
    let 찾은상품 = props.shoes.find( x=> x.id==id);

    // css를 미리 입려놓은 컴포넌트?
    let 박스 = styled.div`
      padding : 20px;
      border-style: ridge;
    `;
    let 제목 = styled.h4`
      font-size: 25px;
    `;

    // UI 보이고/안보이고하는 상태를 state로 저장
    let [alert, alert변경] = useState(true);
    let [inputData, inputData변경] = useState();

    // 컴포넌트가 mount, update 될때 특정코드 실행할 수 있다
    useEffect(() => {
      let timer = setTimeout( ()=> {
        alert변경(false);
      }, 2000);
    }, [alert]);

    return (
        <div className="container">
          <박스>
            <제목 className="red">상세페이지</제목>
          </박스>
          {
            alert === true
            ? <div className="my-alert">
                <p>재고가 얼마 남지 않았습니다.</p>
              </div>
            : null
          }

          <div className="row">
            <div className="col-md-4">
              <img src={"https://codingapple1.github.io/shop/shoes"+찾은상품.id+".jpg"} width="100%" />
            </div>
            <div className="col-md-6 mt-4">
              <h4 className="pt-5">{찾은상품.title}</h4>
              <p>{찾은상품.content}</p>
              <p>{찾은상품.price}</p>
              <Info 재고={props.재고} />
              <button className="btn btn-danger">주문하기</button>&nbsp;
              <button className="btn btn-danger" onClick={()=>{hist.goBack()}}>뒤로가기</button>
            </div>
          </div>
        </div>
    )
}

function Info() {
  return (
    <p>재고: {props.재고[0]}</p>
  )
}

export default Detail;

재고 정보는 component로 만들어서 넣어보기로

Info 컴포넌트 만들고 props 로 전달 [ App.js > Detail > Info ]

 

props로 하위로 값 전달 [Detail > Info]

<Info 재고={props.재고} />

(Detail.js)
function Info(props) {
  return (
    <p>재고: {props.재고[0]}</p>
  )
}

export default Detail;

state변경함수도 props로 전달 가능

 

생성하는 컴포넌트가 많을 수록 앱은 복잡해진다 -> Context API 혹은 redux를 써야한다고...

 

리액트 사이트 build

사이트를 배포하기 위해선, App.js 파일 그대로 올리는게 아니라

build용 파일을 생성한 후 그걸 올려야 한다.

리액트의 각종 문법 등을 브라우저가 이해하고 해석할수 있도록 html, css 같은 걸로 바꿔준다

 

npm run build [ yarn build]