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

[학습메이트 최기환] Chapter 1-1. 프레임워크 없이 SPA 만들기 #69

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

Conversation

gihwan-dev
Copy link

@gihwan-dev gihwan-dev commented Dec 20, 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) 이벤트 위임

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

과제 셀프회고

좋은 구조를 만들어 보려고 노력했습니다! React와 React-Router-Dom의 구조에 가깝게 만들어 보려고 했던거 같아요. render, navigator, router의 결합도를 최대한 낮추려 했습니다.

라이브러리 폴더의

  • router - BrowserRouter라는 컴포넌트를 제공합니다. path 와 element로 이루어진 객체의 리스트를 인자로 받아, 각 pathname에 맞는 요소를 보여줍니다.
  • render - 렌더링을 합니다. 함수를 인자로 받고, 이 함수는 nesting 될 수 있지만, nesting된 함수의 최종 반환값은 문자열이여야 합니다. 이외에 rerender라는 함수를 노출해서 리렌더링을 어떤 곳에서도 간편하게 일으킬 수 있게 구현했습니다.
  • navigator - 기존의 네비게이터를 SPA에서 이용할 수 있는 형태로 래핑해 반환합니다.

큰 구조는 요정도이고, eventProcessor라는걸 만들어서 이벤트 위임 처리와 이벤트 추가 처리를 하게끔 했는데, 얘는 어디에 놓으면 좋을지... libs에 둬야 할거 같기도 하고.....모르겠습니다!!!


event.stopPropagation();
});
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 이렇게하면 이벤트 위임을 한번에 할 수 있었겠군요..! 멋진 코드 잘 보고갑니다 기환님! 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다:)

Copy link
Contributor

@JunilHwang JunilHwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드리뷰 예시입니다 ㅋㅋ

Comment on lines +9 to +22
const RouteGuard = (
Component: () => string,
options: RouteGuardOptionParams,
) => {
return () => {
if (options.condition()) {
navigator.replace(options.redirectTo);
return options.Fallback;
}
return Component;
};
};

export default RouteGuard;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 ㅋㅋㅋ RouteGuard 를 만들어주셨군요! 좋습니다 👍🏻👍🏻👍🏻

Comment on lines +1 to +5
export type User = {
username: string;
email: string;
bio: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export type User = {
username: string;
email: string;
bio: string;
};
export type User = Record<'username' | 'email' | 'bio', string>

이렇게도 표현할 수 있답니다~!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다! 훨씬 간결해서 좋은거 같아요!

Comment on lines +5 to +16
export function getUser(): User | null {
let user = localStorage.getItem(USER);

if (!user) return null;

return JSON.parse(user);
}

export function setUser(user: User) {
localStorage.setItem(USER, JSON.stringify(user));
rerender();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localStorage를 추상화해서 사용하는 계층이 있으면 좋겠네요!
그리고 store가 바로 render를 의존하고 있는데,
이런것들도 밖에서 처리되면 좋겠어요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다ㅎㅎ 사실 구독 발행 패턴으로 상태관리 스토어를 만들어 볼까 했는데 의지가 거기까지 안가더라고요.... 다음주차 과제는 좀 더 힘을 실어보겠습니다:)

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.

3 participants