Learning Log/Project

[project] naweki 1차 프로젝트 회고

자척개 2023. 2. 20. 10:37
반응형

0. 프로젝트 소개

  • 스포츠 용품을 판매하고 도전이라는 가치를 전달하는 온라인 커머스 플랫폼 나이키 모티브 코딩 프로젝트입니다. 나이키는 웹페이지에서 회원가입 시 얻을 수 있는 혜택을 강조하고 간편한 회원가입 절차를 통해 회원가입을 유도하고 있습니다. 이를 위해 배송이 중요한 사이트이나 회원가입시 주소를 입력받지 않고 결제 시 정확한 주소를 입력하게 합니다. 또한 주문 시에 회원인 경우 무료 배송임을 강조하여 회원이 얻을 수 있는 혜택을 강조합니다.

 

 

 

1. 전체 페이지 시연 영상

https://drive.google.com/file/d/1K7N8V5zpr32S3dHisy2GXMtWi-Bjva7e/view?usp=sharing

 

 

2. 맡은 부분과 실제 구현 모습

Nav

  • 구현 기능 :
  • 메뉴 상단에 회원일 시 '고객님 안녕하세요' 문구 노출되고, 비회원일 시 회원가입과 로그인으로 이동하도록 구현
  • 메뉴 리스트에 mouse enter시 드롭다운 메뉴 노출되고 클릭 시 해당 메뉴로 이동 (new release 클릭 시 신상품 목록으로, men 클릭 시 남성 제품 목록으로 이동함)
  • 드롭다운 메뉴까지 마우스가 움직여도 메뉴가 닫히지 않고, 드롭다운 메뉴의 뒷 배경은 어둡게 처리하여 드롭다운 메뉴를 강조함
  • 검색창에 키워드 검색 시 해당하는 제품을 이미지와 함께 노출하여 사용자의 편의성을 높임
  • 아이콘 클릭 시 각 메뉴로 이동하여 모든 페이지에서 페이지간 이동이 자유롭도록 구현

 

 

제품리스트 페이지

  • 구현 기능 :
  • 백엔드 서버에 저장된 상품 데이터 불러와서 출력
  • 페이지 왼쪽 sidebar에서 lifestyle/jordan 등 해당 카테고리 클릭 시 해당하는 제품만 노출
  • 왼쪽 sidebar에서 색깔과 성별의 경우 버튼을 통해 카테고리 접고 펴는 기능 구현
  • 정렬기준 클릭 시 드롭다운 메뉴 보여줌
  • 사용자가 한눈에 제품을 인식할 수 있도록 한 페이지에 제품 3개씩 보여주고 버튼 형식으로 페이지네이션 구현

 

 

결제 페이지

  • 구현 기능 : 
  • 백엔드 서버에 저장된 장바구니 데이터 불러와서 출력
  • input 창에 입력 후 버튼 클릭 시 입력된 데이터 불러오도록 구현
  • 버튼 클릭 시 다음 절차 컴포넌트 보여주도록 구현
  • 맨 마지막에 주문 완료 시 백엔드로 데이터 전송하도록 구현

 

 

 

3. 진행과정에서 blocker과 해결 방법

첫 번째 blocker : nav에서 메뉴 별 다른 드롭다운 메뉴 데이터 보여주기

blocker : new release에 해당하는 드롭다운 메뉴의 상수데이터와 men/women/kids에 해당하는 드롭다운 메뉴의 상수데이터가 달라 마우스가 움직이면 다른 데이터를 보여줘야 했습니다.

 

nav의 드롭다운 메뉴

 

해결방법 : 처음에는 단순하게 mouse hover로 드롭다운 메뉴를 보여주도록 구현했습니다. 그러다보니, 마우스가 드롭다운 메뉴로 내려가면 드롭다운 창이 닫혀버렸습니다. 그래서 mouse enter라는 이벤트를 알게 되었고 이를 적용했습니다.

그리고 onMouseEnterList라는 함수를 만들 때 id를 parameter(매개변수)자리에 넣어줬으며, jsx <> 안에서 마우스 이벤트를 호출할 때 함수를 호출해주는 방식(() => onMouseEnterList(menu.id))으로 구현했습니다.

 

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { MENU_DATA } from '../data/menuData';
import NewMenuBox from '../NewMenuBox/NewMenuBox';
import OtherMenuBox from '../OtherMenuBox/OtherMenuBox';
import './Menu.scss';

const Menu = () => {
  const [isShown, setIsShown] = useState(false);
  const [menuId, setMenuId] = useState(0);

  const onMouseEnter = () => setIsShown(true);
  const onMouseLeave = () => setIsShown(false);
  // id를 parameter 자리에 넣어줍니다
  const onMouseEnterList = id => setMenuId(id);

  return (
    <div className="menu">
      <ul className="menuLists" onMouseEnter={onMouseEnter}>
        {MENU_DATA.map(menu => {
          return (
            <Link className="toProductList" key={menu.id} to="/products">
              <li
                className="menuList"
                // onmouseenter 시 함수를 호출해줍니다
                onMouseEnter={() => onMouseEnterList(menu.id)}
                id={menu.id}
              >
                {menu.name}
              </li>
            </Link>
          );
        })}
      </ul>
      {menuId === 1 ? (
        <NewMenuBox
          className="menubox"
          isShown={isShown}
          onMouseLeave={onMouseLeave}
          onMouseEnter={onMouseEnter}
        />
      ) : (
        (menuId === 2 || menuId === 3 || menuId === 4) && (
          <OtherMenuBox
            className="menubox"
            isShown={isShown}
            onMouseLeave={onMouseLeave}
            onMouseEnter={onMouseEnter}
          />
        )
      )}
    </div>
  );
};

export default Menu;

 

 

두 번째 blocker : query parameter를 통해 필터링 기능 구현하기

blocker : 아직 동적 라우팅에 익숙치 않아서 쿼리 스트링을 사용하는 것 자체가 어려웠습니다. 그리고 나이키가 특히 카테고리를 다양하게 분류해서(style, gender, color, ...) 이 필터링 기능을 다 구현하는 것은 어렵다고 판단하여 style 카테고리에 대한 필터링만 진행하자고 결정했습니다. 우선 쿼리 스트링을 사용해야 하는 것을 알겠는데 이를 어떻게 적용해야 할지 잘몰랐습니다.

 

이 필터링 기능을 구현

 

해결방법 : 구글링과 위코드 세션을 복습하며 다른 사람들의 코드를 따라쳐봤고, 이를 응용해 제가 필요한 부분을 구현했습니다. 해결 과정에서 console.log를 활용해 에러를 해결해나갔고 필터링 기능을 구현할 수 있었습니다.

 

import React, { useEffect, useState } from 'react';
import { useLocation, useSearchParams } from 'react-router-dom';
import Aside from './Aside/Aside';
import Banner from './Banner/Banner';
import Product from './Product/Product';
import { CATEGORY_DATA } from './Aside/data/categoryData';
import './ProductList.scss';

const ProductList = () => {
  const [products, setProducts] = useState([]);
  const [isFilterClicked, setIsFilterClicked] = useState(false);
  
  // useLocation hook을 이용했습니다
  const location = useLocation();
  const category = location.search;
  const [searchParams, setSearchParams] = useSearchParams();
  const limit = searchParams.get('limit');
  const page = searchParams.get('page');

  useEffect(() => {
  // 쿼리스트링으로 카테고리 필터링 기능을 구현했습니다
    fetch(
      `http://10.58.52.114:3000/products${category}?page=${page}&limit=${limit}`,
      {
        method: 'GET',
      }
    )
      .then(res => {
        return res.json();
      })
      .then(data => {
        setProducts(data.data);
      });
  }, [page, limit, category]);

  const onClickFilter = () => {
    setIsFilterClicked(prev => !prev);
  };

  const movePage = pageNumber => {
    searchParams.set('page', (pageNumber - 1) * 3);
    setSearchParams(searchParams);
  };

  return (
    <main className="productList">
      <Banner onClickFilter={onClickFilter} />
      <div className="contentWrapper">
        <Aside
          isFilterClicked={isFilterClicked}
          products={products}
          CATEGORY_DATA={CATEGORY_DATA}
        />
        <div className="productWrapper">
          <Product products={products} isFilterClicked={isFilterClicked} />
        </div>
      </div>
      <div>
        <button onClick={() => movePage(1)}>1</button>
        <button onClick={() => movePage(2)}>2</button>
        <button onClick={() => movePage(3)}>3</button>
      </div>
    </main>
  );
};

export default ProductList;

 

 

4. 잘한 점과 아쉬운 점

잘한 점

  • 꼼꼼한 기록과 스케줄 관리 :
  • notion과 trello를 이용해 각자의 진행 상황을 꼼꼼히 기록하여 진행상황을 파악하기 수월했습니다. trello로 각 페이지 별 구체적인 진행상황을 확인했고, notion을 통해 daily meeting을 기록하고 공유해야 하는 내용을 정리했습니다.
  •  daily meeting 전 notion에 해당 미팅에서 공유해야 하는 내용을 미리 작성하고 미팅에 임해 프론트와 백이 소통하는 데 많은 도움이 됐습니다. 또한 프론트에서 구현하는 기능을 어떤 식으로 백엔드에 설명해야 할지도 배울 수 있었습니다.
  • notion에서 프론트와 백엔드가 공유해야 하는 데이터를 따로 정리하여 상호간의 소통을 원활하게 했습니다.

우리팀의 trello

 

우리팀의 notion

 

데일리 미팅 전 기록

 

프론트와 백엔드 공유 데이터 정리

 

 

아쉬운 점

  • 보이는 기능을 구현하는 것에만 집중하여 페이지의 레이아웃에 대해 깊게 생각하지 못했습니다. 그러다 보니 처음부터 컴포넌트를 잘 분리하지 못했고, 프로젝트를 진행하면서 컴포넌트를 합쳤다 나눴다하면서 시간을 허비했습니다. 그래서 다음 프로젝트 때는 페이지 분석을 꼼꼼히 하여 어떤 기능을 왜 구현해야 하는지 세세히 작성할 계획입니다.

 

 

5. 다음 프로젝트에 임하는 자세

  • 코더가 아닌 개발자가 되자 : 단순히 기능 하나를 더 구현하는 것보다 이 기능이 왜 필요하고 왜 내가 이 기능을 구현해야 하는지 생각하며 구현하겠습니다.

 

  • 누가 봐도 이해할 수 있도록 말하고 기록하자 : 나의 진행상황은 어디쯤이고 어떤 기능을 어떻게 구현하고 있는지 말과 기록 모두 명확하게 표현할 것입니다. 첫 프로젝트이다보니 어떤 식으로 기능에 대해 설명하고 전달해야 하는지 소통방식이 미숙했습니다. 두 번째 프로젝트에서는 먼저 글을 통해 나의 생각과 진행과정을 자세히 정리하고, 정리한 내용을 바탕으로 남들이 쉽게 이해할 수 있는 언어로 소통하겠습니다.
반응형