React

[React] Nutriguide 프로젝트 코드 리뷰

Puft 2024. 3. 7. 23:14

이어서 InputMenuPage입니다.

 

식단 입력 페이지인데 이 부분은 어느정도 chatGPT의 도움을 받았기 때문에

 

리뷰를 해보려고 합니다.

 

U.I는 antd라는 프레임워크를 사용했습니다.

 

import React, { useState } from 'react';
import { Typography, Input, Form, Button, Select, message, Modal } from 'antd';
import styles from '../css/Button.css';
import '../css/InputPage.css';

function InputMenuPage({  }) {

  const { Option } = Select;

  // 각 요일에 해당하는 식단과 선택된 요일을 관리하는 state
  const [weeklyMenu, setWeeklyMenu] = useState({
    monday: [],
    tuesday: [],
    wednesday: [],
    thursday: [],
    friday: [],
    saturday: [],
    sunday: []
  });
  const [selectedDay, setSelectedDay] = useState('monday'); // 기본값은 월요일
  const [inputValue, setInputValue] = useState('');
  const [modalVisible, setModalVisible] = useState(false);

  const onDescriptionChange = (event) => {
    const { value } = event.target;
    setInputValue(value);
  };

  const onDayChange = (value) => {
    setSelectedDay(value);
  };

  const onSubmit = event => {
    event.preventDefault();
    const newMenu = inputValue.split(/[, ]+/).filter(item => item.trim() !== ''); // 쉼표 또는 공백으로 구분하여 입력값 처리
    setWeeklyMenu(prevMenu => ({
      ...prevMenu,
      [selectedDay]: [...prevMenu[selectedDay], ...newMenu]
    }));
    setInputValue('');
    const formattedMenu = newMenu.join(', '); // 등록된 식단을 쉼표로 구분하여 표시
    message.success(`${selectedDay.charAt(0).toUpperCase() + selectedDay.slice(1)}에 다음 식단이 추가되었습니다: ${formattedMenu}`);
  };

  const deleteMenu = (day) => {
    setWeeklyMenu(prevMenu => ({
      ...prevMenu,
      [day]: []
    }));
    message.success(`${day.charAt(0).toUpperCase() + day.slice(1)}의 식단이 삭제되었습니다.`);
  };

  const showModal = () => {
    setModalVisible(true);
  };

  const handleCancel = () => {
    setModalVisible(false);
  };

  return (
    <div className='inputPage' style={{ backgroundColor: 'beige', display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh' }}>
      <div style={{ maxWidth: '700px', background: 'white', padding: '40px', borderRadius: '20px' }}>
        <div className='input-logo2'>식단 정보</div>
        <Form onSubmit={onSubmit}>
          {/* 요일 선택 */}
          <Form.Item label="요일">
            <Select defaultValue="monday" onChange={onDayChange}>
              <Option value="monday">월요일</Option>
              <Option value="tuesday">화요일</Option>
              <Option value="wednesday">수요일</Option>
              <Option value="thursday">목요일</Option>
              <Option value="friday">금요일</Option>
              <Option value="saturday">토요일</Option>
              <Option value="sunday">일요일</Option>
            </Select>
          </Form.Item>
          {/* 선택된 요일에 대한 식단 입력 폼 */}
          <Form.Item label="식단">
            <Input
              onChange={onDescriptionChange}
              value={inputValue}
            />
          </Form.Item>
          <div style={{ textAlign: 'center' }}>
            <Button className={`${styles.btn} }`} onClick={onSubmit}>
              등록하기
            </Button>
            <Button onClick={showModal} style={{ marginLeft: '10px' }}>등록된 식단 </Button>
          </div>
        </Form>
      </div>
      <Modal
        title="등록된 식단"
        visible={modalVisible}
        onCancel={handleCancel}
        footer={[
          <Button key="back" onClick={handleCancel}>닫기</Button>
        ]}
      >
        {Object.keys(weeklyMenu).map(day => (
          <div key={day}>
            <p>{day.charAt(0).toUpperCase() + day.slice(1)}: {weeklyMenu[day].join(', ')}</p>
            <Button onClick={() => deleteMenu(day)} type="default">식단 삭제</Button>
          </div>
        ))}
      </Modal>
    </div>
  );
}

export default InputMenuPage;

 

코드입니다.

 

각 요일별로 복수의 식단을 입력 받아야하는데 입력 받을 때 쉼표와 공백을 기준으로 입력받아야 합니다.

 

먼저 각 요일별로 state를 만들어 줍니다.

 

const [weeklyMenu, setWeeklyMenu] = useState({
    monday: [],
    tuesday: [],
    wednesday: [],
    thursday: [],
    friday: [],
    saturday: [],
    sunday: []
  });

 

state는 식단을 여러 개 입력 받아야 하므로 배열로 만들어 줍니다.

 

const onDescriptionChange = (event) => {
    const { value } = event.target;
    setInputValue(value);
  };

  const onDayChange = (value) => {
    setSelectedDay(value);
  };

 

그리고 식단과 요일의 상태변경 함수를 만들어 줍니다.

 

const onSubmit = event => {
    event.preventDefault();
    const newMenu = inputValue.split(/[, ]+/).filter(item => item.trim() !== ''); // 쉼표 또는 공백으로 구분하여 입력값 처리
    setWeeklyMenu(prevMenu => ({
      ...prevMenu,
      [selectedDay]: [...prevMenu[selectedDay], ...newMenu]
    }));
    setInputValue('');
    const formattedMenu = newMenu.join(', '); // 등록된 식단을 쉼표로 구분하여 표시
    message.success(`${selectedDay.charAt(0).toUpperCase() + selectedDay.slice(1)}에 다음 식단이 추가되었습니다: ${formattedMenu}`);
  };

 

쉼표와 공백으로 단어를 구분하는 작업은 onSubmit에서 이뤄집니다.

 

파이썬에서만 보던 split함수를 Javascript에서도 쓰더군요.

 

공백을 기준으로 문자열을 나눠주는 함수입니다.

 

newMenu에서는

  1. split(/[, ]+/): inputValue 문자열을 정규 표현식 /[, ]+/에 따라 분할합니다. 이 정규 표현식은 쉼표 또는 공백을 기준으로 분할합니다.
  2. filter(item => item.trim() !== ''): 앞서 분할된 배열에서 각 요소에 대해 trim() 메서드를 사용하여 양쪽의 공백을 제거한 후, 그 결과가 빈 문자열이 아닌 요소들로 이루어진 새로운 배열을 생성합니다.

그리고 이것을 setWeeklyMenu를 통해서 이전에 있던 메뉴에 더해서 삽입해줍니다.

 

 

 

const formattedMenu = newMenu.join(', ');

 

여기서는 모달에 쉼표로 메뉴들이 보이게끔 새로운 변수에 메뉴룰 저장합니다.

 

const deleteMenu = (day) => {
    setWeeklyMenu(prevMenu => ({
      ...prevMenu,
      [day]: []
    }));
    message.success(`${day.charAt(0).toUpperCase() + day.slice(1)}의 식단이 삭제되었습니다.`);
  };

 

여기서는 메뉴를 삭제하는 작업을 합니다.

 

배열의 내용을 삭제하고 삭제 메세지를 출력합니다.

 

const showModal = () => {
    setModalVisible(true);
  };

  const handleCancel = () => {
    setModalVisible(false);
  };

 

ModalVisible이라는 함수를 통해서 Modal의 스위치 역할을 합니다.

return (
    <div className='inputPage' style={{ backgroundColor: 'beige', display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh' }}>
      <div style={{ maxWidth: '700px', background: 'white', padding: '40px', borderRadius: '20px' }}>
        <div className='input-logo2'>식단 정보</div>
        <Form onSubmit={onSubmit}>
          {/* 요일 선택 */}
          <Form.Item label="요일">
            <Select defaultValue="monday" onChange={onDayChange}>
              <Option value="monday">월요일</Option>
              <Option value="tuesday">화요일</Option>
              <Option value="wednesday">수요일</Option>
              <Option value="thursday">목요일</Option>
              <Option value="friday">금요일</Option>
              <Option value="saturday">토요일</Option>
              <Option value="sunday">일요일</Option>
            </Select>
          </Form.Item>
          {/* 선택된 요일에 대한 식단 입력 폼 */}
          <Form.Item label="식단">

 

여기서는 요일별로 선택할 수 있는 Select BOX를 생성합니다.

 

  <Form.Item label="식단">
            <Input
              onChange={onDescriptionChange}
              value={inputValue}
            />
          </Form.Item>
          <div style={{ textAlign: 'center' }}>
            <Button className={`${styles.btn} }`} onClick={onSubmit}>
              등록하기
            </Button>
            <Button onClick={showModal} style={{ marginLeft: '10px' }}>등록된 식단 </Button>
          </div>
        </Form>

 

식단을 입력하는 Input 상자와

 

등록하기, 등록된 식단 버튼을 생성합니다.

 

<Modal
        title="등록된 식단"
        visible={modalVisible}
        onCancel={handleCancel}
        footer={[
          <Button key="back" onClick={handleCancel}>닫기</Button>
        ]}
      >
        {Object.keys(weeklyMenu).map(day => (
          <div key={day}>
            <p>{day.charAt(0).toUpperCase() + day.slice(1)}: {weeklyMenu[day].join(', ')}</p>
            <Button onClick={() => deleteMenu(day)} type="default">식단 삭제</Button>
          </div>
        ))}
      </Modal>

 

antd의 Modal 컴포넌트를 사용해서 상태창을 띄웁니다.

 

여기서는 요일별로 메뉴를 보여주고 식단 삭제 버튼을 통해서 삭제할 수 있습니다.

 

식단 정보 입력 폼

 

뭔가 입력창만 있는 것이 휑해서 디자인을 다시 고려해 봐야할 것 같습니다.

 

식단 Modal

 

이 부분도 버튼의 위치를 조정할 필요가 있을 것 같습니다.

 

다음 시간에는 U.I를 개선하고 새로운 페이지를 만들어보겠습니다.

 

읽어주셔서 감사합니다!