본문 바로가기
React를 같이 배워보자

React 마지막 간단한 프로젝트 2일차- menu화면

by 멈추지않아 2022. 3. 1.
완성본:https://github.com/qjawns0222/hompage.git

자 이제 시작입니다 두번째로 쉬운거입니다 반대로말하면 세번째로 어려운거죠 .....

나 저번 강의처럼 Menu.module.css Menu.jsx Menucontainer.jsx 세개를 추가해주세요

Menu.module.css

.menus {
  display: flex;
  justify-content: space-around;
  align-items: center;
  height: 40vh;
  margin: 1% 10%;
}
.menus > * {
  margin: 50% 10%;
}
.menus > * > .name {
  display: flex;
  width: 100%;
  justify-content: center;
  margin: 2% 0%;
}
.menus > * > .price {
  display: flex;
  width: 100%;
  justify-content: center;
  margin: 2%;
}
.menus > * > .buttons {
  display: flex;
  width: 100%;
  justify-content: center;
  margin: 2%;
}
.menus > * > .buttons > * {
  margin: 5%;
  padding: 2%;
}

.menus > * > .buttons > .minus {
  width: 15%;
  height: 15%;
  font-size: 24px;
  border-radius: 50%;
  font-weight: bolder;
}
.menus > * > .buttons > .plus {
  width: 15%;
  height: 15%;
  font-size: 24px;
  border-radius: 50%;
  font-weight: bolder;
}
.menuinput {
  border: none;
  height: 24px;
  width: 70px;
  text-align: center;
}
.addition {
  display: flex;
  flex-direction: column;

  width: 100%;
}
.addition > .title {
  display: flex;
  justify-content: center;
}
.addition > .hr {
  display: flex;
  margin: auto;
  width: 50%;
  justify-content: center;
}
.addition > .requests {
  display: flex;
  justify-content: center;
  width: 100%;
  margin: 2% 0%;

  justify-content: center;
}
.request {
  width: 50%;
  height: 20vh;
  text-align: start;
  font-size: 20px;
  font-weight: bolder;
  resize: none;
}
.orders {
  display: flex;
  width: 100%;
  justify-content: center;
  margin: 5% 0%;
}
.orders > .order {
  width: 20%;
  font-weight: bolder;
  font-size: 24px;
  border-radius: 5px;
  color: rgb(238, 174, 116);
  background-color: rgb(64, 164, 231);
}
@media screen and (max-width: 700px) {
  .menus > * {
    display: flex;
    flex-direction: column;
    margin: auto;
    margin-right: 15%;
    width: 15vh;
    text-align: center;
  }
  .menus img {
    padding-left: 10%;
    width: 20vh;
  }
  .menus > * > .buttons {
    width: 200px;
    text-align: start;
    margin-left: 0px;
  }

  .menus > * > .buttons > .minus {
    width: 120%;

    font-size: 24px;
    border-radius: 100%;
    font-weight: bolder;
  }
  .menus > * > .buttons > .plus {
    width: 120%;

    font-size: 24px;
    border-radius: 50%;
    font-weight: bolder;
  }
  .menus > * > .buttons > input {
    width: 210%;

    font-size: 24px;
  }
}

작성

page/Menu.jsx

import React from "react";
import Menucontainer from "../container/Menucontainer";
export default function Menu() {
  return (
    <div>
      <Menucontainer />
    </div>
  );
}

작성

그럼이제 container부분을 만들어 보겠습니다.

import React from "react";

import Menu from "../Components/Menu";

export default function Menucontainer() {
  return <Menu />;
}

여기가 기본 형식 여기서 부터 시작이 됩니다

그럼 container에서  무엇이 필요한지 부터 알기위해서 Components.Menu.jsx를 먼저 만들어보겠습니다.

import React from "react";
import Form from "./Form";
import style from "./css/Menu.module.css";
export default function Menu({
  gimbab,
  odeng,
  addition,
  gimminus,
  gimplus,
  odengminus,
  odengplus,
  odengchange,
  gimchange,
  additionchange,
  addorder,
}) {
  return (
    <Form>
      <div className={style.menus}>
        <div className={style.item}>
          <div className={style.imgs}>
            <img
              width={200}
              className={style.img}
              alt="#"
            />
          </div>
          <div className={style.name}>김밥</div>
          <div className={style.price}>2000원</div>
          <div className={style.buttons}>
            <button className={style.minus} onClick={gimminus}>
              -
            </button>
            <input
              type="number"
              onChange={gimchange}
              value={gimbab}
              className={style.menuinput}
            />
            <button className={style.plus} onClick={gimplus}>
              +
            </button>
          </div>
        </div>
        <div className={style.item}>
          <div className={style.imgs}>
            <img
              className={style.img}
              width={200}
              alt="#"
            />
          </div>
          <div className={style.name}>오뎅</div>
          <div className={style.price}>500원</div>
          <div className={style.buttons}>
            <button className={style.minus} onClick={odengminus}>
              -
            </button>

            <input
              type="number"
              onChange={odengchange}
              value={odeng}
              className={style.menuinput}
            />

            <button className={style.plus} onClick={odengplus}>
              +
            </button>
          </div>
        </div>
      </div>
      <div className={style.addition}>
        <h3 className={style.title}>요청 사항</h3>
        <hr className={style.hr}></hr>
        <div className={style.requests}>
          <textarea
            value={addition}
            onChange={additionchange}
            className={style.request}
            placeholder="요청사항을 입력하세요"
          />
        </div>
      </div>

      <div className={style.orders}>
        <button className={style.order} onClick={addorder}>
          주문
        </button>
      </div>
    </Form>
  );
}

이렇게 만들것입니다. 

gimbab : 김밥 몇개 주문할것인지를 변수에 담기 위해 필요한 변수
  odeng,: 오뎅 몇개 주문할것인지변수에 담기 위해 필요한 변수
  addition,: 요청사항을 저장할 변수
  gimminus,: 클릭시 김밥갯수를 줄여줄  함수
 
  gimplus,: 클릭시 김밥갯수를 늘여줄  함수
  odengminus,: 클릭시 오뎅갯수를 줄여줄  함수
  odengplus,: 클릭시 김밥갯수를 줄여줄  함수
  odengchange,: 작성시 오뎅갯수를 바꺼줄 함수
  gimchange,: 작성시 김밥갯수를 바꺼줄 함수
  additionchange,: 요청사항 작성시 내용을 바꺼줄 함수
  addorder,: 작성한 내용을 저장소에 저장해줄 함수

이렇게 각각의 용도가 있습니다. 이것을 menu에서 바로 작성하면 가독성이 안좋기 때문에 container에서 작성해서 전달해주는 것입니다.

그럼 다시 Menucontainer로 이동해서 하나씩 만들어보겠습니다

const [odeng, setOdeng] = useState(0);
const [gimbab, setGimbab] = useState(0);
const [addition, setAddition] = useState("");
이렇게 김밥 오뎅 요청사항을 저장해줄 변수를 만들고 가각 기본값을 넣어줬습니다.
 
const gimminus = () => {
    setGimbab(gimbab - 1);
  };
  const gimplus = () => {
    setGimbab(gimbab + 1);
  };
  const odengminus = () => {
    setOdeng(odeng - 1);
  };
  const odengplus = () => {
    setOdeng(odeng + 1);
  };
버튼 클릭시 변수 내용 변경은 usestate로 만든 함수로 작동시켰습니다
 
 const gimchange = (e) => {
    setGimbab(e.target.value);
  };
  const odengchange = (e) => {
    setOdeng(e.target.value);
  };
  const additionchange = (e) => {
    setAddition(e.target.value);
  };

이렇게 타자로 쳤을때 데이터를 변경할것을 이렇게 그 값으로 변경이 가능합니다.

여기서 e는 자동으로 넘어오게 됩니다. 특별한 설정 없이 다른거랑 똑같이 작성해도 자동으로 e에 정보가 저장되서 옵니다.

  const time = new Date();
  const times = time.getHours() + ":" + time.getMinutes();
  const navigate = useNavigate();
  const value = useContext(store);
 const addorder = () => {
    if (gimbab === 0 && odeng === 0) {
      alert("주문을 추가해주세요");
      return;
    }
    if (value.id <= 10000) {
      value.id = value.id + 1;
    } else {
      value.id = 1;
    }

    value.data.push({
      id: value.id,
      gim: gimbab,
      odeng: odeng,
      addition: addition,
      date: times,
    });
    alert("순번을 기억해주세요\n" + "순번:" + value.id);

    setGimbab(0);
    setOdeng(0);
    setAddition("");
    navigate("/order");
  };

 

여기가 menu중에 가장 어려운 부분입니다.

time은 현재 시간을 나타내기위해 클래스르 만든것입니다. Date라는 클래스는 기본적으로 만들어져있고 저렇게 사용함으로써 시간과 분 을 얻어올수 있습니다.

const value = useContext(store);

 이부분은 우리가 만들었던 저장소를 가르키게 됩니다.

 const navigate = useNavigate();

이것은 창을 이동하기위해 필요한 요소입니다.

이제 함수를 설명하면

처음 if문에서 오뎅과 김밥이 둘다 0이면 주문을 입력하라고 창을 뛰워주는 역할을 합니다

두번째는 id값이 무한히 증가하는 것을 막기위해 10000이 넘어가면 다시 1로 변하게 해서 id값이 너무 커지는걸 막아주고 만들때마다 id값을 증가시켜줍니다.

그리고 push를 이용해서 배열로 저장소에 데이터를 저장해주게 됩니다.

그리고  alert로 자기가 몇번인지 기억하라고 알려주게 됩니다.

그리고나서 다시 menu창에는 다 초기화시켜서 추가로 주문을 더할수 있도록 설정하고

그리고 주문이 됬는지 확인하라고 order 로 이동 시켜줍니다.

아직 제대로 만들어주지 않아서 이런창이 나오게 됩니다.

  <Menu
      odeng={odeng}
      gimbab={gimbab}
      addition={addition}
      gimminus={gimminus}
      gimplus={gimplus}
      odengminus={odengminus}
      odengplus={odengplus}
      gimchange={gimchange}
      odengchange={odengchange}
      additionchange={additionchange}
      addorder={addorder}
    />
 여기서 각자 데이터의 이름으로 전달해주게 됩니다.
그리고 Menu.jsx 에서
export default function Menu({
  gimbab,
  odeng,
  addition,
  gimminus,
  gimplus,
  odengminus,
  odengplus,
  odengchange,
  gimchange,
  additionchange,
  addorder,
})
 이런식으로 받아서 사용가능합니다.
 

그래서 다 정리하면

import React, { useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import Menu from "../Components/Menu";
import store from "../context/store";
export default function Menucontainer() {
  const time = new Date();
  const times = time.getHours() + ":" + time.getMinutes();
  const navigate = useNavigate();
  const value = useContext(store);
  const [odeng, setOdeng] = useState(0);

  const [gimbab, setGimbab] = useState(0);
  const [addition, setAddition] = useState("");
  const gimminus = () => {
    setGimbab(gimbab - 1);
  };
  const gimplus = () => {
    setGimbab(gimbab + 1);
  };
  const odengminus = () => {
    setOdeng(odeng - 1);
  };
  const odengplus = () => {
    setOdeng(odeng + 1);
  };
  const gimchange = (e) => {
    setGimbab(e.target.value);
  };
  const odengchange = (e) => {
    setOdeng(e.target.value);
  };
  const additionchange = (e) => {
    setAddition(e.target.value);
  };
  const addorder = () => {
    if (gimbab === 0 && odeng === 0) {
      alert("주문을 추가해주세요");
      return;
    }
    if (value.id <= 10000) {
      value.id = value.id + 1;
    } else {
      value.id = 1;
    }

    value.data.push({
      id: value.id,
      gim: gimbab,
      odeng: odeng,
      addition: addition,
      date: times,
    });
    alert("순번을 기억해주세요\n" + "순번:" + value.id);

    setGimbab(0);
    setOdeng(0);
    setAddition("");
    navigate("/order");
  };
  return (
    <Menu
      odeng={odeng}
      gimbab={gimbab}
      addition={addition}
      gimminus={gimminus}
      gimplus={gimplus}
      odengminus={odengminus}
      odengplus={odengplus}
      gimchange={gimchange}
      odengchange={odengchange}
      additionchange={additionchange}
      addorder={addorder}
    />
  );
}

이런식으로 나오게 됩니다.

이렇게 menu화면은 작성이 완료되었습니다.  다음에는  order창을 만들어보도록 하겠습니다.