[항해 플러스 프론트엔드 코스 3기] 1주차 회고

osohyun0224·2024년 9월 28일
6
post-thumbnail

안녕하세요 프론트엔드 개발자 Garden, 오소현입니다:)
저는 요즘 항해 플러스 프론트엔드 3기 코스 과정에 참여하면서 공부하고 있는데요!
오늘은 그 첫 주차의 회고를 진행해보려고 합니다 !

[1] 과제 회고

우선 이번주차 첫 과제는 " 프레임워크 없이 SPA 만들기 Part 1" 과제였습니다!
과제를 하면서 주요한 토픽이 있었는데 아래의 3가지를 한 번 보겠습니다 :)

주요한 토픽 3가지

Topic 1. 모두 함수형에서 일부 클래스로 리팩토링

함수 위주로 구현했던 리팩토링 전 코드

특히 아래 대표적으로 로그인 페이지 컴포넌트에 사용되는 로직과, 테스트 코드의 전역에러 핸들링도 특정 페이지 컴포넌트에 사용되게 하는
비효율적인 코드를 구현하였습니다.

[이전] 로그인 페이지 컴포넌트
export default function LoginPage() {
  function renderLoginPage() {
    document.getElementById('root').innerHTML = `
      <main class="bg-gray-100 flex items-center justify-center min-h-screen">
..로그인 UI
      </main>
      <div id="error-message" class="text-red-500 text-center mt-4"></div> 
    `;
  }

  window.addEventListener('error', function (e) {
    console.error('전역 에러 발생:', e.error);
    displayErrorMessage(e.error ? e.error.message : '에러가 발생했습니다.');
    e.preventDefault();
  });

  function handleLoginSubmit(e) {
    e.preventDefault();
    try {
      const username = e.target.querySelector('#username').value;

      if (!username) {
        throw new Error('이름과 비밀번호를 입력해주세요');
      }

      const userData = { username, email: '', bio: '' };

      localStorage.setItem('user', JSON.stringify(userData));
      userStore.updateUser(userData);

      Router.navigate('/profile');
    } catch (error) {
      displayErrorMessage(error.message);
    }
  }

  function setupEventListeners() {
    const loginForm = document.getElementById('login-form');
    if (loginForm) {
      loginForm.addEventListener('submit', (e) => {
        try {
          handleLoginSubmit(e);
        } catch (error) {
          console.error("로그인 중 오류 발생:", error);
          displayErrorMessage(error.message);
        }
      });
    }
  }

  function displayErrorMessage(message) {
    const errorContainer = document.getElementById('error-message');
    if (errorContainer) {
      errorContainer.innerHTML = errorMessage({ message });
    }
  }

코치님의 멘토링으로 클래스의 이점과, 전역 에러 핸들링을 최상단에서 관리하면 좋을 것 같다는 팀원분의 피드백을 받아 다음과 같은 패턴으로 리팩토링을 시작했습니다.

  • 사용자에게 보여지는 UI 컴포넌트(Views)는 클래스로 구현하자. 그리고 UI 컴포넌트는 사용자에게 보여지는 역할 만 하자.
[개선] 로그인 페이지 컴포넌트 - class
class LoginPage {
  render() {
    return `
    <main class="bg-gray-100 flex items-center justify-center min-h-screen">
      <div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
        <h1 class="text-2xl font-bold text-center text-blue-600 mb-8">항해플러스</h1>
        <form id="login-form">
          <div class="mb-4">
            <input type="text" id="username" name="username" placeholder="이메일 또는 전화번호" class="w-full p-2 border rounded">
          </div>
          <div class="mb-6">
            <input type="password" id="password" name="password" placeholder="비밀번호" class="w-full p-2 border rounded">
          </div>
          <button type="submit" class="w-full bg-blue-600 text-white p-2 rounded font-bold">로그인</button>
        </form>
        <div class="mt-4 text-center">
          <a href="#" class="text-blue-600 text-sm">비밀번호를 잊으셨나요?</a>
        </div>
        <hr class="my-6">
        <div class="text-center">
          <button class="bg-green-500 text-white px-4 py-2 rounded font-bold">새 계정 만들기</button>
        </div>
      </div>
    </main>
  `;
  }
}

export default LoginPage;
  • 서비스를 전체적으로 관리하고, UI과 모델을 연결하는 제어 컨트롤러의 역할을 하는 main.js에서 실행되도록 리팩토링을 진행했습니다.
    이때 로그인 페이지에 의존하던 전역 에러 핸들링 로직을 main에서 함수로 제어하게 되었습니다
Storage.removeData("user");
const root = document.querySelector("#root");
const loginInfo = session();
const router = createRouter();

const routes = {
  "/": () => new HomePage(loginInfo).render(),
  "/login": () => new LoginPage().render(),
  "/profile": () => new ProfilePage(loginInfo).render(),
  "/404": () => new NotFoundPage().render(),
  "/error": () => "오류 발생! 의도적인 오류입니다."
};

Object.keys(routes).forEach(path => router.addRoute(path, routes[path]));

router.render();
window.addEventListener("popstate", router.render);
window.addEventListener("error", () => router.navigate("/error"));
root.addEventListener("click", handleClick);
root.addEventListener("submit", handleSubmit);

.. 아래 함수 로직들

결론적으로 UI 컴포넌트들은 클래스로 리팩토링, 내부 로직들은 기능이 명확하게 보이고, 비즈니스 로직들은 함수로 구현해서 처리되고 있습니다. 현재 아래와 같은 폴더 구조에서 클래스와 함수를 적절히 사용해 구현했습니다 !

📦 
├─ src
│  ├─ __tests__
│  │  ├─ advanced.test.js
│  │  └─ basic.test.js
│  ├─ components
│  │  ├─ ErrorBoundary.js // 클래스
│  │  ├─ Footer.js //클래스
│  │  └─ Header.js //클래스
│  ├─ main.js // 함수
│  ├─ pages
│  │  ├─ HomePage.js //클래스
│  │  ├─ LoginPage.js //클래스
│  │  ├─ NotFoundPage.js/ /클래스
│  │  └─ ProfilePage.js //클래스
│  ├─ router.js  // 함수
│  ├─ setupTests.js
│  └─ utils
│     ├─ session.js  // 함수
│     ├─ storage.js // 함수
│     └─ store.js // 함수

리팩토링 후 클래스와 함수로 분리된 현재의 코드

Topic 2. 폴더 구조

📦 
├─ src
│  ├─ __tests__
│  │  ├─ advanced.test.js
│  │  └─ basic.test.js
│  ├─ components
│  │  ├─ ErrorBoundary.js
│  │  ├─ Footer.js
│  │  └─ Header.js 
│  ├─ main.js // 프로젝트의 전반적인 컨트롤러 역할 페이지 및 라우터 설정하고, 상황에 맞는 세션과 이벤트를 관리하는 로직
│  ├─ pages
│  │  ├─ HomePage.js 
│  │  ├─ LoginPage.js
│  │  ├─ NotFoundPage.js
│  │  └─ ProfilePage.js
│  ├─ router.js  // 사용자 인증 상태에 따른 조건부 라우팅과 페이지 렌더링을 통해 사용자 경험을 관리하는 로직
│  ├─ setupTests.js
│  └─ utils
│     ├─ session.js  // 사용자의 전역 상태 관리 및 상태를 조회하거나 업데이트하는 로직
│     ├─ storage.js // 세션 정보를 객체 내에 저장하고, 로그인 상태와 사용자 정보를 관리하는 로직
│     └─ store.js // 로컬 스토리지 관리 로직

현재 각각의 기능을 가진 함수들이 위와 같은 폴더 구조로 구현되어있는데 Model과 Controller 에 해당하는 main.js와 router.js는 src 내부 최상단에 위치하고, 나머지 상태관리는 모두 utils에 넣어 더 나은 폴더 구조를 고민했습니다 !

Topic 3. 불필요한 랜더링

기능과 구조를 나눠서 분리해 구현하다보면, 테스트 불필요하게 랜더링이 되는 테스트 실행이 있었습니다.

불필요하게 여러 번 렌더링 되는 초기 코드

위의 문제를 해결하기 위해서 render() 함수로 불필요한 렌더링을 줄이고자 노력했습니다!

[2] 멘토링과 과제 리뷰

디테일하게 작성할 수 없어 아쉽지만 팀원분들과 코드 리뷰하고, 코치님의 피드백으로 더 디테일하게 코드의 문제점이나 개선점을 파악할 수 있어서 좋았다!

[3] 과제 결과

크크 둘다 이번주차 Best Practice 선정 !! ✨✨

[4] 다음 주를 맞이하며,,

Keep : 현재 만족하고 계속 유지할 부분

과제를 해결하는 과정 속에서 시간 분배를 첫 주차에 잘했다고 생각했습니다.
주말에 과제를 시작하면서 이번주차 과제가 나에게 얼마나 어렵고 시간이 걸릴지 파악을 할 수 있어서 평일까지 완성을 다 할 수 있었다고 생각합니다.

Problem : 개선이 필요하다고 생각하는 문제점

문제점은 학습 자료를 잘 활용하지 않은 점이 아쉬웠다!

Try : 문제점을 해결하기 위해 시도해야 할 것

학습 자료를 소화할 정도로 많은 시간을 투자해 읽어보고 학습해보자

[5] 항해 플러스 다음 기수 합류하기

저는 현재 정말 열심히 몰입해서 공부하고 있는데요!

저도 3기 입과할때 슈퍼 얼리버드 기간에 합류해 추천인 할인까지해서 제일 최대 할인된 가격에 합류할 수 있었습니다 ㅎㅎ

방금 말씀드린 추천인 제도로 [추천인] 코드에 “fWHY9o” 를 입력하시면 20만 원 추가 할인 혜택이 있으니 결제하실때 꼭 추천인 할인 코드도 함께 입력해주세요!

제 항해 플러스 프론트엔드 후기 글을 보고 궁금한 사항이 있으시다면 댓글이나, 벨로그 프로필 이메일, 링크드인으로 문의주세요 :)

profile
Garden / Junior Frontend Developer

0개의 댓글