Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6팀 방재현] [Chapter 1-1] 프레임워크 없이 SPA 만들기 #50

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

CRITICBANGGU
Copy link

@CRITICBANGGU CRITICBANGGU commented Dec 19, 2024

과제 체크포인트

기본과제

1) 라우팅 구현:

  • History API를 사용하여 SPA 라우터 구현
    • '/' (홈 페이지)
    • '/login' (로그인 페이지)
    • '/profile' (프로필 페이지)
  • 각 라우트에 해당하는 컴포넌트 렌더링 함수 작성
  • 네비게이션 이벤트 처리 (링크 클릭 시 페이지 전환)
  • 주소가 변경되어도 새로고침이 발생하지 않아야 한다.

2) 사용자 관리 기능:

  • LocalStorage를 사용한 간단한 사용자 데이터 관리
    • 사용자 정보 저장 (이름, 간단한 소개)
    • 로그인 상태 관리 (로그인/로그아웃 토글)
  • 로그인 폼 구현
    • 사용자 이름 입력 및 검증
    • 로그인 버튼 클릭 시 LocalStorage에 사용자 정보 저장
  • 로그아웃 기능 구현
    • 로그아웃 버튼 클릭 시 LocalStorage에서 사용자 정보 제거

3) 프로필 페이지 구현:

  • 현재 로그인한 사용자의 정보 표시
    • 사용자 이름
    • 간단한 소개
  • 프로필 수정 기능
    • 사용자 소개 텍스트 수정 가능
    • 수정된 정보 LocalStorage에 저장

4) 컴포넌트 기반 구조 설계:

  • 재사용 가능한 컴포넌트 작성
    • Header 컴포넌트
    • Footer 컴포넌트
  • 페이지별 컴포넌트 작성
    • HomePage 컴포넌트
    • ProfilePage 컴포넌트
    • NotFoundPage 컴포넌트

5) 상태 관리 초기 구현:

  • 간단한 상태 관리 시스템 설계
    • 전역 상태 객체 생성 (예: 현재 로그인한 사용자 정보)
  • 상태 변경 함수 구현
    • 상태 업데이트 시 관련 컴포넌트 리렌더링

6) 이벤트 처리 및 DOM 조작:

  • 사용자 입력 처리 (로그인 폼, 프로필 수정 등)
  • 동적 컨텐츠 렌더링 (사용자 정보 표시, 페이지 전환 등)

7) 라우팅 예외 처리:

  • 잘못된 라우트 접근 시 404 페이지 표시

심화과제

1) 해시 라우터 구현

  • location.hash를 이용하여 SPA 라우터 구현
    • '/#/' (홈 페이지)
    • '/#/login' (로그인 페이지)
    • '/#/profile' (프로필 페이지)

2) 라우트 가드 구현

  • 로그인 상태에 따른 접근 제어
  • 비로그인 사용자의 특정 페이지 접근 시 로그인 페이지로 리다이렉션

3) 이벤트 위임

  • 이벤트 위임 방식으로 이벤트를 관리하고 있다.

과제 셀프회고

기술적 성장

  • 새로 학습한 개념
    • 이벤트 버블링
    • History API
    • 해시 라우팅
    • 테스트 유지보수

여러번 사용해봤지만, 정확한 명칭과 개념을 알지 못하고 '그냥 이렇게 하니깐','예시 코드에 있던데?' 라는 생각으로 개발을 했습니다. 자세하게 찾아보고 공부하니깐 개발이 더 재미있었습니다~!

코드 품질

매직넘버가 없어서 잘 읽히는 코드를 만들고 싶었습니다. 그래서 ROUTE_DATA 배열에 접근할 때, 사용할 index를 따로 관리 했습니다. 코드가 잘 읽히는(개인적인 생각) 코드인 것 같긴한데... 로직 부분에서는 과연 잘 읽히는 것인가? 에 대한 물음표는 아직 남아있습니다..!

학습 효과 분석

과제 피드백

잘 보면 다 찾을 수는 있지만.. 테스트 코드에 있는 요구조건이 있어 조금 아주조금... 헷갈렸습니다..! 앞으로는 과제를 할 때, 테스트 코드를 먼저 보고 해보겠습니다!
(ex. 로그인이 되지 않은 상태에서 "/profile" 경로로 접근하면, 로그인 페이지로 리다이렉션 된다.)

리뷰 받고 싶은 내용

  1. navAction 함수 내에서 e.target.id"logout"일 때 localStorage에서 user정보 사라지고 /login으로 navigate 처리되도록 작성하였습니다. 다만, run 시켜 제가 테스트를 하면 원하는 순서로 동작하는데, 이 로직이 테스트 코드에서는 동작하지 않는 이유는 무엇인가요?! 추가로 어떻게 해결을 해야할지 방향을 모르겠습니다..!

    • 문제 상황

      • main.js에서 DOMContentLoaded 이벤트가 발생하면, body에 click 이벤트를 위임하여 navAction(e) 가 동작하도록 설정하였습니다.
        //src/main.js
        document.addEventListener("DOMContentLoaded", () => {
            document.body.addEventListener("click", (e) => {
                navAction(e);
            });
            router();
        });
      • navAction 함수는 클릭 이벤트가 발생했을 때, 클릭된 대상(e.target)의 id를 확인하여 logoutAction 함수를 호출합니다.
        //src/utils/evnetHandler.js
        export function logoutAction(e) {
            e.preventDefault();
            removeLocalStorage("user");
            navigateTo("/login");
        }
        
        export function navAction(e) {
            if (e.target.id === "logout") {
                logoutAction(e); // id가 'logout'인 경우 실행
                return;
            }
            if (e.target.tagName === "A") {
                e.preventDefault();
                navigateTo(e.target.pathname);
            }
        }
      • 그러나 테스트에서 id="logout"을 가진 <a> 태그를 클릭해도 logoutAction 함수가 호출되지 않습니다.
    • 대처

      • render 함수 실행 시, id="logout"을 가진 요소를 찾아와 있으면 event를 추가해줬습니다.
        //src/router/Router.js
        const render = (view) => {
            const page = Layout(view);
            root.innerHTML = page;
            const logoutButton = document.getElementById("logout");
            if (logoutButton) {
                logoutButton.addEventListener("click", (e) => {
                    e.preventDefault();
                    removeLocalStorage("user");
                });
            }
        };
    • 문제라고 생각한 이유

      • 중복된 코드라고 생각합니다.
        • main.js에서 이미 같은 동작을 한번 했는데, render가 될 때, 또 event를 연결시킨다는게 중복된 코드라고 생각합니다.
      • 불필요한 작동을 한다고 생각합니다.
        • logout 이벤트를 연결하지 않는 상황 (ex. 404 page, login page 렌더링시, logout button은 없습니다. , 사용자가 로그인을 하지 않은 상황이라면 id='logout'인 button은 없습니다.)

          logoutButton이 존재 하는지 (굳이)비교해줘야 합니다.
  2. 현재 작성된 Layout 컴포넌트의 확장성을 높일 수 있는 방법이 무엇이 있을까요?

    • 문제 상황
        const Layout = (element) => {
          return `
          <div class="bg-gray-100 min-h-screen flex justify-center">
            <div class="max-w-md w-full">
              ${element.path === "/" || element.path === "/profile" ? Header() + NavBar() : ""}
              ${element.view()}      
              ${element.path === "/" || element.path === "/profile" ? Footer() : ""}
              </div>
          </div>    
          `;
        };
      • 현재 코드는 조건문으로 path를 분기 처리하고 있어 다음과 같은 확장성 문제를 갖고 있다고 생각합니다.
        • 새로운 path를 추가해야 할 경우, 조건문을 계속 수정해야 합니다.
        • 각 경로에 따라 Header, NavBar, Footer와 같은 공통 요소의 조합이 다를 경우, 조건문이 더 복잡해질 가능성이 있습니다.
        • 유지보수성과 가독성이 떨어지며, 컴포넌트의 역할이 명확하지 않아지는 문제가 발생할 수 있습니다.
    • 개발 의도
      1. 왜 Layout Component을 분리하였는가?
        • 중복 요소를 방지하고, 재사용성을 높이기 위해 Layout Component를 작성하였습니다.
      2. React에서 보통 원하는 요소를 가운데 껴서 만드는 Layout은 children을 요소로 받아와 렌더링 하는데, 왜 element 객체를 받아와서 element.view()로 렌더링을 하는가? view()만 props로 받아오면 되는 것 아닌가?
        • path에 따라서 Layout이 다르게 그려지기 때문에 조건문을 추가하여 Header, NavBar, Footer를 렌더링 하도록 했습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant