본문 바로가기

프론트엔드관련 책예제실습정리/CO.APP(react)

03-tab만들기까지 예제

**scss useContext 는 쓰지 않음

 

//index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
//index.js
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
//App.js
import React, { useState } from "react";
import {Navbar,Container,Nav, NavDropdown,Button,Jumbotron} from "react-bootstrap";
import "./App.css";
import Detail from "./Detail";
import { Route, Link, Switch } from "react-router-dom";
import Data from "./data.js";
import axios from "axios";

function App() {
  // shoes useState를 Detail.js에 적어도되지만
  // 중요한 데이터의 경우 여기에 적어야함.역방향전송이어렵기때문
  const [shoes, shoes변경] = useState(Data);
  let [재고, 재고변경] = useState([10, 11, 12]);

  return (
    <div className="App">
      <Navbar bg="light" expand="lg">
        <Container>
          <Navbar.Brand href="#home">React-Bootstrap</Navbar.Brand>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="me-auto">
              <Nav.Link as={Link} to="/">
                Home
              </Nav.Link>
              <Nav.Link as={Link} to="/detail">
                Detail
              </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중복을 막아주고 첫 path를 보여줌 */}
      <Switch>
        <Route exact path="/">
          <Jumbotron>
            <p>
              Using a series of utilities, you can create this jumbotron, just
              like the one in previous versions of Bootstrap. Check out the
              examples below for how you can remix and restyle it to your
              liking.
            </p>
            <Button variant="outline-secondary">Secondary</Button>
          </Jumbotron>
          <div className="container">
            <div className="row">
              {shoes.map((a, i) => {
                return <Card shoes={shoes[i]} i={i} />;
              })}
            </div>
            <button
              className="btn btn-primary"
              onClick={() => {
                //fetch는 json을 object로 바꿔주지 않음
                axios
                  .get("https://codingapple1.github.io/shop/data2.json")
                  .then((결과) => {
                    console.log(결과.data);
                    shoes변경([...shoes, ...결과.data]);
                  })
                  .catch(() => {
                    console.log("실패했어요");
                  });
              }}
            >
              더보기
            </button>
          </div>
        </Route>

        {/* url의 파라미터문법  */}
        <Route path="/detail/:id">
          <Detail shoes={shoes} 재고={재고} 재고변경={재고변경} />
        </Route>
      </Switch>
    </div>
  );
}
function Card(props) {
  return (
    <div className="col-md-4" key="id">
      <img
        src={
          "https://codingapple1.github.io/shop/shoes" + (props.i + 1) + ".jpg"
        }
        width="100%"
        alt="사진1"
      ></img>
      <h4>{props.shoes.title}</h4>
      <p>
        {props.shoes.content}& {props.shoes.price}
      </p>
    </div>
  );
}
export default App;
//detail.js
import React, { useEffect, useState } from "react";
import { useHistory, useParams } from "react-router-dom";
import styled from "styled-components";
import { Nav } from "react-bootstrap";
import { CSSTransition } from "react-transition-group";
import "./Detail.css";

let box = styled.div`
  padding: 20px;
`;
let 제목 = styled.h4`
  font-size: 25px;
  color: ${(props) => props.색상};
`;
const Detail = (props) => {
  let [alert, alert변경] = useState(true);
  let [입력값, 입력값변경] = useState("");
  let [누른탭, 누른탭변경] = useState(0);
  let [스위치, 스위치변경] = useState(false);

  useEffect(() => {
    let 타이머 = setTimeout(() => {
      alert변경(false);
    }, 2000);
    console.log("안녕");
    return () => {
      clearTimeout(타이머);
    };
  }, [alert]);

  let history = useHistory();
  let { id } = useParams();
  return (
    <div className="container">
      <box>
        <제목 색상={"blue"}>상세페이지</제목>
      </box>
      {입력값}
      <input
        onChange={(e) => {
          입력값변경(e.target.value);
        }}
      />
      {alert === true ? (
        <div className="my-alert2">
          <p>재고가 얼마 남지 않았습니다.</p>
        </div>
      ) : null}

      <div className="row">
        <div className="col-md-6">
          <img
            src="https://codingapple1.github.io/shop/shoes1.jpg"
            alt="img"
            width="100%"
          />
        </div>
        <div className="col-md-6 mt-4">
          <h4 className="pt-5">{props.shoes[id].title}</h4>
          <p>{props.shoes[id].content}</p>
          <p>{props.shoes[id].price}원</p>
          <Info 재고스={props.재고[0]}></Info>
          <button
            className="btn btn-danger"
            onClick={() => {
              props.재고변경([9, 8]);
            }}
          >
            주문하기
          </button>
          <button
            className="btn btn-danger"
            onClick={() => {
              history.goBack();
              //abcd경로로 이동하세요
              // history.push('/abcd')
            }}
          >
            뒤로가기
          </button>
        </div>
      </div>

      <Nav className="mt-5" variant="tabs" defaultActiveKey="link-0">
        <Nav.Item>
          <Nav.Link
            eventKey="link-0"
            onClick={() => {
              스위치변경(false);
              누른탭변경(0);
            }}
          >
            Active
          </Nav.Link>
        </Nav.Item>
        <Nav.Item>
          <Nav.Link
            eventKey="link-1"
            onClick={() => {
              스위치변경(false);
              누른탭변경(1);
            }}
          >
            Option 2
          </Nav.Link>
        </Nav.Item>
      </Nav>

      <CSSTransition in={스위치} classNames="wow" timeout={500}>
        <TabContent 누른탭={누른탭} 스위치변경={스위치변경} />
      </CSSTransition>
    </div>
  );
};
function TabContent(props) {
  useEffect(() => {
    props.스위치변경(true);
  });
  if (props.누른탭 === 0) {
    return <div>0번째 내용입니다</div>;
  } else if (props.누른탭 === 1) {
    return <div>1번째 내용입니다</div>;
  } else if (props.누른탭 === 2) {
    return <div>2번째 내용입니다</div>;
  }
}

function Info(props) {
  return <p>재고: {props.재고스}</p>;
}
export default Detail;
//Detail.css
body {
  margin: 0;
}

div {
  box-sizing: border-box;
}

.red {
  color: red;
}

.wow-enter {
  opacity: 0;
}

.wow-enter-active {
  opacity: 1;
  transition: all 500ms;
}
//data.js
export default [
  {
    id : '0',
    title : "White and Black",
    content : "Born in France",
    price : 120000
  },

  {
    id : 1,
    title : "Red Knit",
    content : "Born in Seoul",
    price : 110000
  },

  {
    id : 2,
    title : "Grey Yordan",
    content : "Born in the States",
    price : 130000
  }
] 
//package.json
{
  "name": "prototype-shop",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "axios": "^0.21.1",
    "bootstrap": "^5.0.2",
    "react": "^17.0.2",
    "react-bootstrap": "^1.6.1",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "react-transition-group": "^4.4.2",
    "styled-components": "^5.3.0",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}