Solo-Project ( React_Vending-machine ) 회고록

이준석·2023년 5월 14일
0

Project

목록 보기
5/7
post-thumbnail

1. 프로젝트 소개

자판기웹페이지를 React로 구현

  • 기존에 제작했던 프로젝트를 리액트로 리팩토링 작업
  • 자판기 시스템과 같이 음료를 선택해 음료의 금액만큼 지불
  • 아래 이미지와 같은 피그마파일을 타겟으로 UI 제작
  • 자체적으로 과제 미션을 만들어 제작

사용기술

React, styled-components
웹페이지 확인하러 가기
React_Vending-machine 코드 github 확인
피그마 파일
*Figma 저작권은 제주코딩베이스캠프에게 있습니다.

2. 리팩토링 진행을 하는 이유와 이점

비록 한페이지로만 만든 작은 프로젝트지만 바닐라 자바스크립트로 하다보니 불편했던 점이있다.

  1. 코드의 복잡성
  • 일일히 DOM에 직접 접근해야 하기 때문에 코드가 지저분해지는 것 같다.
    - 모든 JS코드가 하나의 파일에서 관리 (해당 부분은 모듈로 관리가능하기 때문에 제외)
    => 컴포넌트로 분리하여 관리
  1. 중복되는 HTML코드
  • 컴포넌를 사용함으로써 중복되는 코드들을 한 번에 해결이 된다.
  1. 상태관리
  • 상태관리라는 개념을 몰랐는데, 리액트를 공부하면 알게되었다.
    바닐라 자바스크립트론 그저 데이터를 변경한다면, 아무 제어 없이 DOM에 접근해 바꾸기만
    하면 땡이였다.
    상태관리라는 개념이 들어온다면, 조금 더 안전하게 관리할 수 있다.
    어떤 코드로 인해 해당 값이 바뀌었는지 추적하기가 쉬워 관리가 좋다.

3. 프로젝트를 진행하며 고민했던 부분이나 어려웠던 부분 (또는 이슈, 에러)

2023-01-08 노션페이지
1. 컴포넌트의 설계 시 어떤 기준으로 나누면 좋을 지

  • 고려했던 부분
    • 여러 상태들과 상태의 변화에 영향을 받는 컴포넌트들의 구분
      • A라는 상태가 업데이트될 때 어떤 컴포넌트들이 영향을 받고 어떻게 연결이 되었는지
      • 해당 컴포넌트끼리 묶어 놓는다면, 관리하기 쉬울 것이라 생각함
    • UI를 중심으로 구분하기
  • File Setting

    .root
    ├── public
    └── src
    │   ├── img
    │   ├── app.js
    │   ├── components
    │   │   ├── common (공통컴포넌트)
    │   │   └── in (왼쪽 큰블럭 : 자판기)
    │   │   └── out (오른쪽 큰블럭 : 나의 정보)


  1. styled-components로 이미지 url를 들고 올때 상단에 주소를 import해서 가져온다
import logoImg from './img/logo.png';
const Logo = styled.h1`background: no-repeat center / 100% 100% url(${logoImg});`

  1. 웹페이지의 전체를 백그라운드로 처리할려고
    height: 100% 를 사용해도 먹지 않는다.

    해결방법으로 height: 100vh 를 사용했다
    하지만 문제점으로 스크롤이 생기는 부분까지 되지 않는다

    • 그 이유는 vh의 단위는 보이는 화면을 기준으로 했기 때문에 화면을 넘어서 스크롤이 생긴 부분은 적용되지 않는다
    • ⇒ 해결방법으로 height: 130vh 을 사용

2023-01-09 노션페이지
1. 이슈: 상위 태그(빈 div태그)에 백그라운드 컬러를 지정
⇒ 하위 태그 아래 margin부분에 적용되지 않음
2. 이유: 상위태그의 height가 내부 태그에 맞춰서 크기를 조정
- margin끼리 맞닿을 때 상쇄
3. ⇒ 자식 요소의 마진이 더 크든 작든 상관없이 상쇄된 마진은 부모 박스의 바깥으로만 렌더링이 됩니다. (부모를 벗어남)

4. 해결방법: padding 또는 border 값을 주어 벽을 만들어준다.
관련 블로그

2023-01-10 노션페이지
2023-01-11 노션페이지

Styled-components에서 Global CSS 적용하는 방법 알아보기

  • 글로벌 CSS를 사용하는 이유
    • 공통된 작업을 하나하나 하는 것이 비효율
    • 만약 전체 수정이 필요할 때 컴포넌트 하나하나 찾아가며 수정해야 함
  • ThemeProvider 사용
    • ThemeProvider 태그를 컴포넌트 최상단에 감싸준다
    • 프롭스로 theme를 설정
    • Context API를 이용해 해당 프롭스의 값들은 하위에 있는 styled컴포넌트들은 모두 사용가능
    • 자판기에서 적용할 수 있는 부분: 버튼 디자인, 컬러
  • createGlobalStyle() 사용
    • createGlobalStyle() 함수로 생성한 전역 스타일 컴포넌트를 애플리케이션의 최상위 컴포넌트에 추가해주면 하위 모든 컴포넌트에 해당 스타일이 일괄 적용

Reset css

  • 역할: HTML코드의 태그들의 CSS영역 기본 값들을 초기화
  • 사용이유: 웹브라우저 마다 defalt 값이 달라 브라우저에 따라 보여지는 화면이 달라짐 (크로스 브라우징)
  • 사용 방법 https://im-designloper.tistory.com/77
    • [ 기존에 사용하던 방법 ( css 파일 추가 ) ]
    • [ npm으로 설치하는 방법 ] (React 사용 시)

2023-01-12 노션페이지
1. 컴포넌트 export 주의

  • export defalt App O (함수로만 보내기)
  • export defalt X

  1. 글꼴 적용 방법
  • 구글웹폰트에 사용할 글꼴 검색
  • 찾아서 추가하고 복사
  • index.html파일에 link태그 추가

  1. CSS 선택자 정리 (nth-:nth-child())
  • 부분 클래스 적용
  • &:nth-child(n + 4) { margin-top: 12px; } ⇒ 4번째부터 적용
    • &은 자신을 가리킴

  1. styled component 확장
  • const StyledButton2 = styled(StyledButton)
  • 기존 styled로 만든 컴포넌트를 확장할 때 () 묶어서 사용
  • 백틱 안에 추가할 코드 작성
  • 주의할 점: export 할 때 일반 컴포넌트 처럼 함수에 넣어서 반환하면 안됨! (그냥 변수 그대로 )
  • 추가 설명 코드 노션 작성

2023-01-15 노션페이지
1. styled component 확장이 아닌 조건에 따른 적용

  • 조금의 코드때문에 확장하는 것 보다 조건에 따른 변경코드 적용 가능
  • 기존의 컴포넌트를 사용하고 프로퍼티만 지정해주면 됨
    • ⇒ 쓸 때 없는 컴포넌트 생성을 없앰
  • 여러 줄의 CSS 코드를 조건부로 보여주고 싶다면 css 를 사용해야합니다.
//예시
import styled, { css } from 'styled-components';

const Circle = styled.div`
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
	// 허그라는 프롭스가 있을 시 아래 적용
  ${props =>
    props.huge &&
    css`
      width: 10rem;
      height: 10rem;
    `}
`;

  1. JSX 주석 사용법
    • {/* 멀티라인으로 사용하고 표현식으로 묶기 */}
    • 태그 안에 프롭의 주석을 남기고 싶을 때
      <div id = 3 // 주석입니다 ></div>

  1. 드롭다운 구현
  • styled-component로 hover 구현 ⇒ css기능만 조작이 가능하고 js의 기능은 조작하지 못함
    해결방법:
    -useState 를 이용한 hover 기능 구현
    - onMouseOver (마우스가 컴포넌트에 있을 때
    - onMouseOut ( 마우스가 컴포넌트에 없을 때

  1. Styled로 생성한 컴포넌트의 선언 위치
  • styled-components 선언은 Component 함수 스코프 외부에 위치 해야하는 규칙을 갖고 있습니다.
  • 관련 블로그

2023-01-17 노션페이지
input컴포넌트 상태 관리

  • 기존에 사용했던 프롭스를 지정해 switch문을 이용함
  • 추가관리가 어려움 ⇒ 생성된 input 컴포넌트 하나하나 다 지정해주어야 함
  • ⇒ 해결방법
    하나의 스테이트로 관리하기
const [inputForm, setInputForm] = useState({
    deposit: '',
    changeCoin: '',
  });

  function inputHandleChange(e) {
    setInputForm((prev) => ({
      ...prev,
      // 스프레드 문법을 쓰는 이유
      // 정적인 값을 할당 시 타겟이 아닌 값에 영향을 줌
     [e.target.name]: e.target.value,
      // e.target.name과 같은 프로퍼티 키를 가진 벨류를 변경
    }));
  }

이벤트에 따른 상태변화 필요 값 정리

  • 어떤 이벤트에는 어떤 값들이 활용되는지 파악
  • 정리한 이유: 이벤트 코드 작성 시 확인
    ex) 입금 이벤트 =>{ 소지금, 잔액, input에 적힌 값 (입금하고자 하는 값)} 필
잔액반환코인반환획 득코인변환코인입금금액입금아이템 선택
소지금OOO
소지코인OOO
잔액OOOO
잔여코인OOOO
장바구니리스트OO
장바구니 총금액OO
할인된 금액OO
내 리스트O
구매한 총금액O
입금 금액O
입금 코인O
장바구니 아이템 개수OO

2023-01-18 노션페이지
1. 코인변환 이벤트 다시 작성
기존의 방법

  • 자판기에 입금되어있는 코인과 현금,
  • 입금되지않은 코인, 현금
    의 각자 스테이트를 만들어 사용
    - 추후 다른 많은 스테이트 사용으로 복잡 가능성이 있음
  • 변경 방법
    1. 관련 있는 데이터끼리 객체로 묶어 관리
      1. (소지한 코인, 자판기 잔여 코인)
        1. const [coin, setCoin] = useState({outCoin: 0, inCoin: 0})
      2. (소지한 현금, 자판기 잔여 현금)
        1. const [money, setMoney] = useState({outMoney: 0, inMoney: 0})

2022-02-08 노션페이지
2022-02-09 노션페이지

  • 스타일이 하나만 사용되는 컴포넌트라도 인라인 작성보다 따로 styled컴포넌트를 생성하는 것이 좋다.

사이드 이펙트 분리

(목표 상태가 변하면 알아서 다른 상태도 렌더링)

  • input상태 분리 ⇒ 자판기 안에 금액이 변경될 대, 소지금이 변경될 때 자동으로 리렌더링
  • depositReducer안에서 사용되는 상태변환은 useEffect를 사용해서 해결하기
  • 자판기에 금액(코인) 입금 시
    • 자판기에 입금된 금액(inCash) 변경 시 자동으로 소지한 금액(outCash)이 변경
  • 자판기에 입금된 금액(코인) 반환 시 ⇒ useEffect로 사용 X
    • 자판기에 입금된 금액(inCash) 변경 시 자동으로 소지한 금액(outCash)이 변경
      • 입금된 금액을 소지한 금액에 더 해야 하지만 입금된 금액이 0으로 바뀌고 Effect가 실행돼 전에 있던 값을 더할 수 가 없음
      • 원래 동작 : outcash = outcash + incashincash = 0
      • Effect로 사용 시 : incash = 0outcash = outcash + incash
      • incash 의 변경으로 Effect가 실행되기 때문

2022-02-23 노션페이지

에러발생

  • 내용
    장바구니에 있는 아이템들을 구매(획득영역으로 이동) 시 장바구니에 총금액이 같이 업데이트되지 않음
    => 장바구니에 담긴 아이템이 없기 때문에 0원으로 업데이트 되야 함
  • 원인
    총금액 표시 부분값(basketTotal)을 useRef로 만들고
    그리고 사이드이펙트로 분리함
    => useEffect에 의존성 배열에 basketList를 넣어 basketList 변경 시 basketTotal도 업데이트 되는 사이드이펙트
  useEffect(() => {
      if (basketList.itemInList.length > 0) {
        basketTotal.curret = basketList.itemInList.reduce(
          (a, b) => a + b.price * basketList.count[b.name],
          0
        );
      } else basketTotal.curret = 0;
  }, [basketList, basketTotal]);

해결방법
=> useEffect에 전달된 콜백 함수는 컴포넌트가 렌더링된 후에 실행된다.
=> 그러므로 값이 마지막에 변경이 되었고, 이미 basketList로 인한 화면 레던링이 끝났고, useRef의 특성으로 변경이 되어도 화면이 렌더링되지 않음
⇒ state로 변경

소감

  • React로 처음 프로젝트를 진행하면서 상태관리 라이브러리를 쓰는 이유를 대충 알게된 것 같다
  • (Prop Drilling)
    하나의 상태를 여러군데 사용이될 때 부모컴포넌트에서 관리했는데 그런 부분에서 코드가 복잡해지는 것 같다
  • 조금 더 공부해서 깔끔한 코드를 작성하고 싶다

0개의 댓글