내가 보려고 만든 개발 공부 일지

넘블 챌린지 - Front-End 본문

그 외 잡다구리

넘블 챌린지 - Front-End

kwangsunny 2021. 11. 29. 00:52

넘블에서 주도하는 챌린지중 프론트엔드 클론 코딩 챌린지에 참여한 후 작성하는 프로젝트 관련 정리 글입니다.

 

리디북스 or 클래스101 의 실제 사이트를 보고 3주 안에 클론 코딩하는것이 임무였고,

필자는 리디북스를 선택하여 개발을 진행했습니다.

API는 넘블에서 제공하는것을 사용하였고 React, Typescript 베이스로 개발하였습니다.

상태 관리는 Redux, 간단한 아이콘은 react-icons 라는 라이브러리를 사용했습니다.

 

필자는 회사를 다니고 있기에 평일에는 거의 작업을 못했고, 주말에 작업을 몰아서 진행하였기 때문에

꽤나 빡센(?) 3주였습니다.. 중간에 삽질도 하면서 아까운 시간을 많이 까먹기도 했지만,, 어찌어찌

할 수 있는데 까지만 구현하고 마무리를 지었습니다. 😵

 

 

 

[ 주요코드 설명 ]

 

1. 홈 화면 렌더링

리디북스는 홈 화면에 다양한 책들을 주제별로 슬라이드 형태로 보여주고 있었기에

받아온 책 리스트를 제 마음대로 기준을 정해 아래와 같이 필터링 하였습니다. 

const filterHighRateBooks = ()=> books.filter(book => book.starRate.rate > 3);
const filterWaitFree = ()=> books.filter(book => book.waitFree);
const filterLotsOfAwards = ()=> books.filter(book => book.author.awards.length > 2);
const filterLotsAuthorCareer = ()=> books.filter(book => book.author.representatives.length > 1);
const filterForGridSlider = ()=> books.slice(0, 9);

 그리고 슬라이드 컴포넌트를 만들어 필터링시킨 책 리스트를 슬라이드 컴포넌트의 prop 으로 넘겨주어 화면을 렌더링 했습니다.

<section className='book-list-box'>
  <Panel title='수상 경력이 다양한 작가의 작품!' dark={true} titleLink={false}>
  	<BookSlider bookList={filterLotsOfAwards()} dark={true}  badge='discount' hideRate={true} hideTotal={true} hidePrice={true}/>
  </Panel>
  <Panel title='사람들이 지금 많이 읽고있는 책' titleLink={false} label={getHourMin()}>
  	<BookGridSlider bookList={filterForGridSlider()} width={50} height={70}/>
  </Panel>
  <Panel title='특별기간 기다리면 무료'>
  	<BookSlider bookList={filterWaitFree()} badge='waitFree'/>
  </Panel>
  <Panel title='베스트 셀러'>
  	<BookGridSlider bookList={filterForGridSlider()} width={80} height={113}/>
  </Panel>
  <Panel title='오늘, 리디의 발견'>
  	<BookSlider bookList={filterLotsAuthorCareer()} hideRate={true}  hidePrice={true} hideTotal={true}/>
  </Panel>
  <Panel title='금주의 추천도서'>
  	<BookSlider bookList={filterHighRateBooks()}  hidePrice={true} hideTotal={true}/>
  </Panel>
</section>

 

2. 세션 체크

로그인 하지 않은 상태에서 알림, 카트, 마이리디 같은 메뉴를 클릭하면 로그인 페이지로 유도가 됩니다.

로그인에 성공시 유저 정보를 sessionStorage 에 user 라는 키값으로 유저 정보를 저장하고 로그아웃을 하면

null 로 세팅합니다.

아래는 로그인 페이지 코드의 일부입니다.

// id, pw 가 일치하면 유저 정보를 sessionStorage 에 저장한다 
const loginSuccess = (user: User)=>{
    user.pw = '';
    onLogin(user);
    sessionStorage.setItem('user', JSON.stringify(user));
    navigate(currentPath || '/');
}

// 입력한 id, pw 체크
const doLogin = async ()=>{
    if(validate()){
        const user: User = await request('login');
        if(user) {
            if(inputs.id === user.id && inputs.pw === user.pw){
                loginSuccess(user);
            }else{
                setWran('아이디 또는 비밀번호를 확인해주세요.');
            }
        }
    }
}

위처럼 유저 정보를 스토리지에 저장해 놓고 카트, 알림, 마이리디 메뉴를 클릭할때 세션을 체크하여 

로그인 화면으로 이동할지 말지를 결정합니다.

export const checkSession = ()=>{
    const user = sessionStorage.getItem('user');
    return user && JSON.parse(user) && JSON.parse(user).id;
}

세션 체크는 어디에서나 할 수 있는 행위이므로 util 함수로 만들어놓고 공통으로 사용했습니다.

 

 

3. 카트에 책 추가하기

책을 클릭하면 해당 책에대한 상세 화면으로 이동하는데 거기서 카트모양 아이콘을 누르게 되면

카트 페이지로 책들이 추가가되고 카트 메뉴에 추가된 책의 수만큼 숫자가 표시됩니다.

// 카트 아이콘 클릭 시
const onClickToCart = ()=>{
    toCart(book);
    // 토스트 메시지 노출
    showMsg({
        msg: '카트에 담았습니다.',
        link: '카트 보기',
        linkCallback: ()=>{
            navigate('/cart');
        }
    });  
}

위처럼 책 상세 화면에서 카트 아이콘 클릭 시, 이벤트 함수에서 책정보(book) 와 노출시킬 메시지 정보를 넘겨줍니다.

// 액션 호출
const toCart = (book: BookData)=>{
    dispatch(addBook(book));
}
const showMsg = (msgInfo: MessageInfo)=>{
    dispatch(pushMsg(<ToastMessageContainer {...msgInfo}/>));
}

액션을 발생시켜 카트에 보여줄 책 리스트를 업데이트 해주고 동시에 메시지도 푸쉬 해줍니다.

 

 

 

 

[ 어려웠던점.. ]

 

프로젝트를 진행하면서 하면서 가장 어려웠던건 이벤트 슬라이더 컴포넌트를 만드는 것이었다.

리디북스 홈 화면을 보면 이벤트 정보를 이미지 슬라이드 형식으로 보여주는 부분이 있다.

이 슬라이드는 좌우 클릭 버튼이 있어서 직접 좌우로 이미지를 이동시킬 수 있고, 약 10초 간격으로

자동 슬라이딩이 된다. 중요한건 슬라이드가 끝에 도달하면 다시 처음 혹은 마지막 이미지가 다음 순서로

나오는 무한 슬라이드라는 점이다.

화면에 보이는 이미지는 세개 이고 슬라이드 할때 이동, 투명화, 높이 변화 같은 애니메이션도 적용되어 있었다.

그렇기에 단순히 이미지가 끝에 닿았을때 리스트의 첫(혹은 마지막) 부분을 마지막으로 이어 붙여주면 되겠지...

생각했으나 그렇게 되면 컴포넌트가 다시 그려지면서 애니메이션 효과없이 뚝뚝 끊기게 렌더링 되는게 문제였다. 

이를 해결하고자 다양한 방법을 시도하고 검색도 치열하게 해봤으나 결국 리디홈화면과 똑같이 구현하지는 못했다..

아직 할일이 산더미인데 이 문제로 시간을 너무 까먹었기 때문에 어쩔 수 없이 다음으로 넘어갔다.

(어떻게 구현하는지 정말 알고싶다)

 

 

 

 

[ 활용한 라이브러리와 이유 ]

 

사용한 라이브러리는 크게 Redux 와 react-icons 두가지 이다.

리덕스는 상태관리 용으로 사용 하였는데, 워낙 레퍼런스도 많고 널리 사용되고 있는 라이브러리라

필자도 리덕스를 사용했다.

 

react-icons 는 간단한 SVG 컴포넌트를 모아놓고 쉽게 import 하여 가져다 쓸 수 있는 라이브러리다.

페이지를 만들다보면 자잘한 아이콘들이 많이 보이는데 그런것들을 이미지로 일일이 검색해서 구하는건

시간이 많이들고 피곤한 일이다.

그래서 간단한 아이콘을 가져다 쓰기엔 react-icons가 가장 적절했다.  

 

  

 

 

[ 느낀점 ]

 

처음엔 3주면 꽤나 넉넉한 시간이라 생각했고 충분히 다 개발을 할 수 있을거라 생각했지만,, 

그것은 필자의 큰 착각이었다.

일단 평일에 작업을 많이 할 수 없어서 아쉬웠고, 주말에 최대한 진행했지만 그것도 중간중간 마주치는

난관에 발목을 잡혀 시간을 꽤 잡아먹었다.

다 구현하지 못한 기능들이 많이 남아서 개인적으로 매우 아쉬운 프로젝트였고 동시에 삽질로 배운것도 많았다.

챌린지 기간내에 완성은 못했지만 이후에 짬을내여 틈틈이 못한 부분들을 마저 구현해나갈 생각이다.

 

Comments