안녕하세요 프론트엔드 개발자 Garden, 오소현입니다:)
저는 요즘 항해 플러스 프론트엔드 3기 코스 과정에 참여하면서 공부하고 있는데요!
오늘은 그 첫 주차의 회고를 진행해보려고 합니다 !
우선 이번주차 첫 과제는 " 프레임워크 없이 SPA 만들기 Part 1" 과제였습니다!
과제를 하면서 주요한 토픽이 있었는데 아래의 3가지를 한 번 보겠습니다 :)
함수형
에서 일부 클래스
로 리팩토링특히 아래 대표적으로 로그인 페이지 컴포넌트에 사용되는 로직과, 테스트 코드의 전역에러 핸들링도 특정 페이지 컴포넌트에 사용되게 하는
비효율적인 코드를 구현하였습니다.
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 });
}
}
코치님의 멘토링으로 클래스
의 이점과, 전역 에러 핸들링을 최상단에서 관리하면 좋을 것 같다는 팀원분의 피드백을 받아 다음과 같은 패턴으로 리팩토링을 시작했습니다.
사용자에게 보여지는 역할
만 하자. 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;
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 // 함수
📦
├─ 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에 넣어 더 나은 폴더 구조를 고민했습니다 !
기능과 구조를 나눠서 분리해 구현하다보면, 테스트 불필요하게 랜더링이 되는 테스트 실행이 있었습니다.
불필요하게 여러 번 렌더링 되는 초기 코드위의 문제를 해결하기 위해서 render() 함수로 불필요한 렌더링을 줄이고자 노력했습니다!
디테일하게 작성할 수 없어 아쉽지만 팀원분들과 코드 리뷰하고, 코치님의 피드백으로 더 디테일하게 코드의 문제점이나 개선점을 파악할 수 있어서 좋았다!
크크 둘다 이번주차 Best Practice 선정 !! ✨✨
과제를 해결하는 과정 속에서 시간 분배를 첫 주차에 잘했다고 생각했습니다.
주말에 과제를 시작하면서 이번주차 과제가 나에게 얼마나 어렵고 시간이 걸릴지 파악을 할 수 있어서 평일까지 완성을 다 할 수 있었다고 생각합니다.
문제점은 학습 자료를 잘 활용하지 않은 점이 아쉬웠다!
학습 자료를 소화할 정도로 많은 시간을 투자해 읽어보고 학습해보자
저는 현재 정말 열심히 몰입해서 공부하고 있는데요!
저도 3기 입과할때 슈퍼 얼리버드 기간에 합류해 추천인 할인까지해서 제일 최대 할인된 가격에 합류할 수 있었습니다 ㅎㅎ
방금 말씀드린 추천인 제도로 [추천인] 코드에 “fWHY9o” 를 입력하시면 20만 원 추가 할인 혜택이 있으니 결제하실때 꼭 추천인 할인 코드도 함께 입력해주세요!
제 항해 플러스 프론트엔드 후기 글을 보고 궁금한 사항이 있으시다면 댓글이나, 벨로그 프로필 이메일, 링크드인으로 문의주세요 :)