출석부-React

김의석 ·2024년 9월 3일

Hello! Poko Ver.2

목록 보기
14/28
post-thumbnail

AttendacnePage.js

import { Layout, Select, Button } from 'antd'

import {Layout, Select, Button } from 'antd';

1. Layout 컴포넌트

  • 역할: Layout 컴포넌트는 페이지의 기본 구조를 구성하는 데 사용. 이를 통해 웹 애플리케이션의 레이아웃을 쉽게 정의.
  • 기능:
    • Layout 컴포넌트는 여러 서브 컴포넌트(Header, Footer, Sider, Content)로 나뉘어 있어, 페이지의 상단, 하단, 사이드바, 본문 영역을 각각 쉽게 설정.

2. Select 컴포넌트

  • 역할: Select 컴포넌트는 사용자가 여러 옵션 중 하나를 선택할 수 있도록 하는 드롭다운 메뉴를 제공.
  • 기능:
    • 선택된 값에 따라 상태를 관리하거나 이벤트를 처리.
    • 기본값을 설정하고, 사용자가 선택을 변경할 때 실행할 함수를 지정.
    • Option 서브 컴포넌트를 사용하여 각각의 선택 항목을 정의.

3. Button 컴포넌트

  • 역할: Button 컴포넌트는 사용자가 클릭할 수 있는 버튼을 생성.
  • 기능:
    • 다양한 타입(primary, default, dashed, link 등)의 버튼을 제공하여, 버튼의 스타일을 쉽게 변경.
    • 버튼 클릭 시 실행할 함수를 지정할 수 있으며, 이로 인해 사용자 인터랙션을 처리.

const [selectedYear, setselectedYear ] = useState(new Data().getFullYear());

const [selectedYear, setselectedYear ] = useState(new Data().getFullYear());

React의 useState 훅을 사용하여 상태값을 생성하고 초기화.

1. useState

useState는 React에서 상태값을 관리하기 위해 사용하는 훅(Hook). 이 훅은 배열을 반환하며, 배열의 첫 번째 요소는 현재 상태값이고, 두 번째 요소는 그 상태값을 업데이트할 수 있는 함수입니다.

훅(Hook)에 대한 기본 개념

React 훅은 기본적으로 함수 컴포넌트에서 상태를 관리하거나 부수효과(side effect)를 처리하기 위해 사용. 주로 사용되는 두 가지 주요 훅은 useState와 useEffect.

2. 상태값 selectedYear

  • selectedYear는 현재 연도를 저장하는 상태값. 이 값은 컴포넌트가 처음 렌더링될 때 new Date().getFullYear()에 의해 초기화.
  • new Date().getFullYear()는 현재 날짜의 연도를 숫자 형식으로 반환. 예를 들어, 2024년이라면 2024가 반환.

3. 상태 업데이트 함수 setSelectedYear

  • setSelectedYearselectedYear 상태를 업데이트하기 위해 사용되는 함수.
  • 사용자가 특정 연도를 선택하거나 다른 방식으로 연도를 변경할 때, 이 함수를 호출하여 selectedYear 상태를 업데이트.
  • 예를 들어, 사용자가 드롭다운 메뉴에서 연도를 선택하면, setSelectedYear(2025)와 같이 호출하여 상태를 2025로 변경.

useEffect

useEffect는 React에서 컴포넌트가 렌더링될 때특정 상태나 props가 변경될 때 실행되는 사이드 이펙트를 처리하기 위해 사용되는 훅(Hook).

useEffect의 기본 개념

useEffect는 다음과 같은 경우에 코드를 실행할 수 있도록 함.

  • 컴포넌트가 처음 렌더링될 때 (마운트)
  • 컴포넌트가 업데이트될 때
  • 컴포넌트가 제거될 때 (언마운트)

useEffect의 역할 및 구조

useEffect는 두 가지 인수를 받습니다:
1. 첫 번째 인수: 실행할 함수. 이 함수는 지정된 의존성(dependencies)이 변경될 때마다 호출.
2. 두 번째 인수: 의존성 배열. 이 배열 안에 나열된 값들이 변경될 때마다 useEffect 안의 함수가 다시 실행. 이 배열을 생략하면 컴포넌트가 렌더링될 때마다 useEffect가 실행. 빈 배열([])을 전달하면 컴포넌트가 처음 마운트될 때만 실행.

AttendancePageuseEffect 설명

useEffect(() => {
    fetchStudents().then(setStudents);
    fetchAttendanceData(selectedYear).then(setAttendanceData);
}, [selectedYear]);

useEffect는 다음과 같은 역할을 한다.

  1. 컴포넌트가 처음 렌더링될 때 실행:

    • fetchStudents() 함수가 호출되어 학생 데이터를 가져온다. 이 함수가 데이터를 성공적으로 가져오면 setStudents 함수가 호출되어 students 상태가 업데이트.
    • fetchAttendanceData(selectedYear) 함수가 호출되어 선택된 연도의 출석 데이터를 가져온다. 이 함수가 데이터를 성공적으로 가져오면 setAttendanceData 함수가 호출되어 attendanceData 상태가 업데이트.
  2. selectedYear 상태가 변경될 때 실행:

    • 사용자가 연도를 변경하면 selectedYear 상태가 업데이트되며, 이로 인해 useEffect가 다시 실행.
    • 새 연도에 맞춰 fetchAttendanceData(selectedYear) 함수가 다시 호출되고, 해당 연도의 출석 데이터를 가져와 attendanceData 상태를 업데이트.

useEffect의 기능 요약

  • 데이터 초기화: AttendancePage 컴포넌트가 처음 렌더링될 때, 학생 목록과 초기 연도의 출석 데이터를 가져온다.
  • 데이터 업데이트: 사용자가 연도를 변경할 때마다 해당 연도의 출석 데이터를 새로 가져온다.
  • 의존성 관리: selectedYear 의존성 배열에 포함되어 있어, 이 값이 변경될 때마다 useEffect 내부의 코드가 다시 실행됩니다.

useEffect의 주의점

  • 의존성 배열: useEffect의 두 번째 인수로 전달된 의존성 배열에 포함된 값이 변경될 때만 useEffect가 다시 실행. 예를 들어, 이 코드에서는 selectedYear가 변경될 때만 출석 데이터를 새로 가져온다.
  • 비동기 작업: fetchStudents()fetchAttendanceData(selectedYear)비동기 함수로, 데이터를 가져오는 동안 컴포넌트는 비동기적으로 동작하며 상태가 업데이트.(axios로 전환, 동기)

Select component

1. <Select> 컴포넌트

<Select> 컴포넌트는 사용자가 여러 옵션 중에서 하나를 선택할 수 있는 드롭다운 메뉴를 제공. 이 컴포넌트는 Ant Design 라이브러리에서 제공하는 UI 컴포넌트.

구조

  • defaultValue={selectedYear}: defaultValue 속성은 드롭다운이 처음 렌더링될 때 기본으로 선택된 옵션을 설정. 여기서는 selectedYear 상태 값이 기본 선택으로 설정됩니다.

  • onChange={(value) => setselectedYear(value)}: onChange 속성은 사용자가 드롭다운에서 다른 옵션을 선택했을 때 실행될 함수를 지정. 여기서는 사용자가 연도를 선택하면 setSelectedYear(value) 함수가 호출되어 selectedYear 상태가 업데이트. 이때 value는 사용자가 선택한 연도.

  • <Option> 요소들: 이 컴포넌트는 [2022, 2023, 2024] 배열을 순회하며 각각의 연도에 대해 <Option> 요소를 생성. <Option> 요소는 keyvalue 속성을 가지며, 사용자가 선택할 수 있는 개별 옵션을 표시. 예를 들어, 사용자가 2023년을 선택하면 2023selectedYear로 설정.

기능

  • 사용자는 드롭다운 메뉴를 통해 연도를 선택.
  • 선택된 연도는 selectedYear 상태로 저장..
  • 사용자가 연도를 변경할 때마다 useEffect 훅이 실행되어, 새로운 연도에 대한 출석 데이터를 가져온다.

componet

모달 디자인 및 출석부 기능 구현 (2024년 9월 12일)


문제

  1. 모달 창 크기 조정 필요:

    • 모달 창의 위아래 높이가 부족하고 좌우 폭이 너무 넓은 문제 발생.
    • 취소 및 등록 버튼이 스크롤에 포함되는 문제.
  2. 디자인 목표:

    • 첫 번째 이미지를 기반으로 모달의 높이 및 너비를 조정하여 두 번째 UI 디자인과 일치하게 구현.
    • 학생 목록만 스크롤되도록 구현하고, 버튼은 스크롤에서 제외하는 방식으로 수정.

문제 해결 과정

  1. 모달 크기 및 높이 조정:

    • CSS 코드를 수정하여 모달의 위아래 높이를 늘림.
    • .modal-formmax-height 값을 조정하여 학생 목록의 최대 높이를 400px로 설정하고, 스크롤을 추가.
    .modal-form {
        max-height: 400px; /* 학생 목록의 최대 높이 */
        overflow-y: auto; /* 학생 목록에만 스크롤 추가 */
        margin-bottom: 20px; /* 학생 목록과 하단 버튼 사이의 간격 */
        padding-right: 10px; /* 스크롤바와 내용 간의 간격 */
    }
  2. 버튼 스크롤에서 제외:

    • position: stickybottom: 0 속성을 추가하여 취소 및 등록 버튼이 항상 하단에 고정되도록 수정.
    • background-color를 추가하여 버튼 영역이 고정되면서 가려지지 않도록 함.
    .modal-footer {
        display: flex;
        justify-content: space-between;
        margin-top: 30px;
        position: sticky;
        bottom: 0;
        background-color: white; /* 고정 시 버튼 영역이 가려지지 않도록 배경색 추가 */
        padding-top: 10px;
    }
  3. 최종 CSS 코드:

    .custom-modal {
        border-radius: 12px;
        padding: 20px;
    }
    
    .modal-header {
        text-align: center;
        margin-bottom: 30px;
    }
    
    .modal-header h2 {
        font-size: 18px;
        font-weight: bold;
    }
    
    .modal-subtitle {
        font-size: 14px;
        color: #757575;
    }
    
    .modal-form {
        max-height: 400px;
        overflow-y: auto;
        margin-bottom: 20px;
        padding-right: 10px;
    }
    
    .form-item {
        background-color: #F0F4FF;
        border-radius: 8px;
        padding: 8px;
        margin-bottom: 10px;
    }
    
    .checkbox {
        width: 100%;
    }
    
    .modal-footer {
        display: flex;
        justify-content: space-between;
        margin-top: 30px;
        position: sticky;
        bottom: 0;
        background-color: white;
        padding-top: 10px;
    }
    
    .cancel-btn {
        background-color: #F5F5F5;
        border: none;
        color: #757575;
        width: 100px;
        height: 40px;
        font-size: 16px;
        border-radius: 8px;
    }
    
    .submit-btn {
        background-color: #1890ff;
        border: none;
        color: white;
        width: 100px;
        height: 40px;
        font-size: 16px;
        border-radius: 8px;
    }
  4. 출석부 모달 기능 구현:

    • 학생 목록을 체크박스로 표시하여 선택 가능하게 만들었으며, 출석부 등록 및 취소 버튼을 통해 사용자 입력을 처리.
    • React 상태 관리(useState)를 통해 체크된 학생 목록을 동적으로 관리하고, 모달을 열고 닫는 동작을 구현.

결과

  • 모달 창의 크기와 버튼 위치를 조정하여 디자인에 맞는 UI를 완성함.
  • 학생 목록에만 스크롤 기능을 적용하고, 버튼은 스크롤에서 제외되어 고정되는 방식으로 수정하여 UX 개선.

모달 생성 과정 및 AttendanceChart 스크롤 추가 작업 (2024년 9월 12일)


모달 생성 과정

  1. 문제:

    • 출석부에 출석을 등록하는 모달 창을 생성해야 함.
    • UI 디자인에 맞춰 모달 크기, 버튼 위치, 스크롤 기능 등을 구현해야 함.
  2. 해결 과정:

    1. Ant Design Modal 컴포넌트 사용:

      • Ant Design의 Modal 컴포넌트를 사용하여 모달을 구현.
      • 모달 상태는 useState를 통해 isModalOpen으로 관리하며, 모달을 열고 닫는 함수(openModal, closeModal)를 각각 정의.
    2. 학생 체크박스 구현:

      • Checkbox 컴포넌트를 사용하여 학생 목록을 출력하고, 각각의 학생을 체크할 수 있도록 구현.
      • checkedStudents 배열로 체크된 학생 목록을 관리하며, handleCheck 함수로 체크 여부를 동적으로 관리.
    3. 등록 및 취소 버튼 구현:

      • 모달 하단에 취소 및 등록 버튼을 배치하였으며, 취소 버튼은 onCancel로 모달을 닫는 기능을 수행하고, 등록 버튼은 선택된 데이터를 콘솔에 출력한 후 모달을 닫도록 구현.
    4. 모달 컴포넌트 분리:

      • 모달 창 코드를 독립적인 컴포넌트(AttendanceModal.js)로 분리하여 유지보수성을 높임.

    모달 관련 주요 코드:

    // AttendancePage.js
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [checkedStudents, setCheckedStudents] = useState([]);
    
    const openModal = () => setIsModalOpen(true);
    const closeModal = () => setIsModalOpen(false);
    
    const handleCheck = (studentId) => {
      setCheckedStudents(prevChecked => 
        prevChecked.includes(studentId)
          ? prevChecked.filter(id => id !== studentId)
          : [...prevChecked, studentId]
      );
    };
    
    const handleSubmit = () => {
      console.log('출석부 등록 완료:', checkedStudents);
      setIsModalOpen(false); 
    };
    
    <AttendanceModal
      isOpen={isModalOpen}
      onClose={closeModal}
      students={students}
      checkedStudents={checkedStudents}
      handleCheck={handleCheck}
      handleSubmit={handleSubmit}
    />

    AttendanceModal 컴포넌트:

    // AttendanceModal.js
    const AttendanceModal = ({ isOpen, onClose, students, checkedStudents, handleCheck, handleSubmit }) => {
      return (
        <Modal
          open={isOpen}
          onCancel={onClose}
          footer={null}
          destroyOnClose={true}
        >
          <div className="modal-header">
            <h2>출석부 등록</h2>
            <p className="modal-subtitle">등록일: {new Date().toLocaleDateString()}</p>
          </div>
    
          <Form layout="vertical" className="modal-form">
            {students.map(student => (
              <Form.Item key={student.id} className="form-item">
                <Checkbox
                  checked={checkedStudents.includes(student.id)}
                  onChange={() => handleCheck(student.id)}
                >
                  {student.name}
                </Checkbox>
              </Form.Item>
            ))}
            <div className="modal-footer">
              <Button onClick={onClose}>취소</Button>
              <Button type="primary" onClick={handleSubmit}>등록</Button>
            </div>
          </Form>
        </Modal>
      );
    };

AttendanceChart 스크롤 추가 작업

  1. 문제:

    • AttendanceChart 컴포넌트에 날짜별 출석 데이터를 표시하는 테이블이 있고, 데이터 양이 많을 경우 가로 스크롤이 필요.
    • UI에서 학생 목록은 고정되며, 날짜별 출석 정보에 대해 가로 스크롤이 가능해야 함.
  2. 해결 과정:

    1. Ant Design Table 컴포넌트 사용:

      • 출석 데이터를 테이블 형태로 표시하기 위해 Ant Design의 Table 컴포넌트를 사용.
      • 각 날짜를 컬럼으로 추가하고, 각 학생의 출석 여부를 또는 로 표시.
    2. 가로 스크롤 추가:

      • Ant Design Tablescroll 속성을 사용하여 가로 스크롤을 추가.
      • scroll={{ x: 'max-content' }} 속성을 사용해 테이블이 화면 크기에 맞지 않으면 가로 스크롤이 생성되도록 설정.
    3. 학생 목록 고정:

      • 학생명 컬럼은 왼쪽에 고정하고, 정보 컬럼은 오른쪽에 고정되도록 설정.
      • 이를 위해 각 컬럼에 fixed: 'left'fixed: 'right' 속성을 추가.

    AttendanceChart 관련 주요 코드:

    // AttendanceChart.js
    const columns = useMemo(() => [
      {
        title: '학생명',
        dataIndex: 'name',
        key: 'name',
        fixed: 'left',
      }, 
      ...data.map(dateEntry => ({
        title: dateEntry.date,
        dataIndex: dateEntry.date,
        key: dateEntry.date,
        render: attendance => (
          <span>{attendance ? '✅' : '❌'}</span>
        ),
      })),
      {
        title: '정보',
        key: 'info',
        fixed: 'right',
        render: () => <a href="#">보기</a>,
      }
    ], [data]);
    
    <Table 
      columns={columns}
      dataSource={dataSource}
      pagination={false}
      scroll={{ x: 'max-content' }}  // 가로 스크롤 추가
      sticky
    />

결과

  • 모달 창 크기를 디자인 요구에 맞춰 조정하고, 학생 목록 스크롤 및 하단 고정 버튼을 구현하여 UI 개선.
  • AttendanceChart에서 가로 스크롤이 가능하게 설정하여 많은 날짜가 표시될 때도 표가 잘 작동하도록 구현.
profile
널리 이롭게

0개의 댓글