hipce 프로젝트 돌아보기

jjo-niixx·2020년 8월 31일
0

wecode 프로젝트

목록 보기
3/5





hipce 영상으로 확인하기

1. hipce를 통해 배운 점

Dynamic Routing

지금까지는 Static Routing을 썼다면 이번 프로젝트에서 처음으로 Dynamic Routing을 써보았다. 이것은 react-router-dom라이브러리에서 제공하는 기능임을 기억하자. 내가 이해한 바로는 주소 끝에 변수를 지정하여 그로 하여금 새로운 페이지로 연결시키는 기능이다. this.props.match.params.id라고 콘솔을 찍어보면 주소 끝에 지정된 변수의 값을 얻을 수 있다. 이를 잘 이용한다면 필터링 된 데이터를 렌더해주는 주소를 구현할 때 유용하게 쓰일 것 같다. 예를 들면 장바구니, 체크아웃 등등 무한한 쓰임새!

import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";

class Routes extends React.Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="detail/:id" component={Detail} />
        </Switch>
      </Router>
    );
  }
}

How to Route path with Question Mark

생각해보자. 쇼핑백 로직을 구현했다. 이 정보를 백엔드에 넘길 때 두 가지의 선택이 존재한다. 전체 주문 or 선택 주문.

전체 주문은 매우 쉽다. 장바구니에 있는 모든 제품의 데이터(id, pricce, quantity..)등을 전달하면 된다. 우리는 API/orders로 데이터를 전달했다. 하지만 선택 주문은 '선택'이라는 것부터 머리아프다. 결과적으로 API/orders?product_id=32&product_id=35로 데이터를 전달했다. 선택된 상품의 id 값을 배열로 만들고 쿼리스트링과 맵으로 뒤의 주소를 완성할 수 있었다.

체크아웃에서 백엔드의 데이터를 받아야 할 때 API/orders, API/orders?product_id=32&product_id=35에서 받게 되었는데 처음에는 동적라우팅으로 주소 끝의 id값을 찾고 싶었다. 하지만 내가 배운 것은 /orders/:id이런 식... 물음표가 붙을 때는 적용되지 않는 방식이었다.

이럴 때는 this.props.location.search를 이용하여 우리가 원하는 product_id: value의 객체를 얻을 수 있다.

import queryString from "query-string";

componentDidMount() {
 const {
   location: { search },
 } = this.props;
 const values = queryString.parse(search);
 if (!values.product_id) {
   fetch(`${API}/orders`)
     .then((res) => res.json())
     .then((res) =>
       this.setState({
         orderItem: res.shoppingbag,
         totalPrice: res.total_price,
       })
     );
 } else {
   fetch(`${API}/orders`)
     .then((res) => res.json())
     .then((res) =>
       this.setState({
         orderItem: res.shoppingbag,
         totalPrice: res.total_price,
       })
     );
 }
 console.log(values) // {product_id: 32, product_id: 35)
 console.log(values.product_id); [32, 35]
}

2-1. 기억하고 싶은 코드 - 이미지 슬라이더

이전 포스팅으로 확인하기

2-2. 기억하고 싶은 코드 - 스크롤 이벤트

메인의 스크롤을 조금만 내려도 다음 화면으로 내려가고, 조금만 올려고 전 화면으로 올라가는 로직을 구현해보았다.

constructor() {
    super();
    this.state = {
      currentPosY: 0,
      scroll: false,
      navBright: false,
      newProduct: [],
      discountProduct: []
    };
  }
  componentDidMount() {
    window.addEventListener("scroll", this.handleScroll);
    })
  }
  handleScroll = () => {
    const { scroll, currentPosY } = this.state;
    const {scrollY} = window;
    if (this.prev > scrollY && scrollY < currentPosY) {
      this.setState(
        { scroll: true, currentPosY: this.state.currentPosY - 969 },
        () =>
          window.scrollTo({ top: this.state.currentPosY, behavior: "smooth" })
      );
    } else if (this.prev < scrollY && scrollY > currentPosY) {
      this.setState(
        { scroll: true, currentPosY: this.state.currentPosY + 969 },
        () =>
          window.scrollTo({ top: this.state.currentPosY, behavior: "smooth" })
      );
    } else if (scroll && scrollY < currentPosY) return;
    this.setState({ scroll: false });
    this.prev = window.scrollY;
  };

2-3. 기억하고 싶은 코드 - 메뉴 탭

모든 사이트의 결제 창에서 꼭 들어가는 부분이다. 사실 메뉴 탭은 이외에도 정말 유용하게 쓰인다. 이전 포스팅인 슬라이더 구현에서도 사용했다. 이벤트 함수를 걸고 인자로 각각 다른 값을 전달하는 것을 기억하자.

//결제 방법을 선택했을 때 나오는 4가지를 컴포넌트화 했다.
const paymentMethod = {
  0: <Card />,
  1: <Transfer />,
  3: <Account />,
  4: <Virtual />,
};
//인자 값으로 전달되는 값을 setState로 업데이트 시켜준다.
handleRadio = (id) => {
    this.setState({
      activeTab: id,
    });
  };
class Checkout extends Component {
  render() {
    return (
      <div className="paymentMethod">
        <label>결제방법</label>
        <span className="methodDetail">
        //input의 radio타입에서 name을 똑같이 맞춰줘야 한개만 클릭하는 것이 가능하다.
        //각각의 radio버튼을 누를 때 다른 인자 값이 전달된다.
          <input
            id="card"
            type="radio"
            name="paymentMethod"
            onChange={() => this.handleRadio(0)}
          />
          <label for="card">
            <span></span>카드 결제
          </label>
        </span>
      </div>
      //상단의 밸류가 컴포넌트인 객체에 setState로 업데이트 된 키 값으로 접근한다.
      {paymentMethod[this.state.activeTab]}
    );
  }
}

2-4. 기억하고 싶은 코드 - 여러 fetch 함수 쓰기

westagram 때는 그저 로그인 창에서 정해진 아이디와 비밀번호를 입력했을 때 토큰 값을 띄울 수 있는 통신에 그쳤다. 하지만 이번에는 백엔드에서 가공한 정보를 fetch로 가져와 내가 만든 화면에 나타낼 수 있었다!!!!! 백엔드에서 잘 만든 데이터를 적재적소에 보여주는 것은 바로 프론트의 몫이라는 것을 명심하고 책임감을 가지자.

메인에서 슬라이더가 두 개가 필요했는데 각각 다른 주소에서 데이터를 가져오는 것이었다. 한 컴포넌트에서 여러 주소에서 데이터가 필요할 때는 Promise.all을 쓰도록 하자. 복잡해보이지만 전혀 그렇지 않다. Promise.all을 붙이고 뒤에 주소로 이루어진 배열을 만들자. 그 이후에는 똑.같.다. 이렇게 하여 메인에서 New Product, Discount 상품에 대한 슬라이더를 만들 수 있었다.

componentDidMount() {
    Promise.all([fetch("http://3.17.134.84:8000/products?tag=new"), fetch("http://3.17.134.84:8000/products?tag=discount")])
    .then(([res1, res2]) => {
      return Promise.all([res1.json(), res2.json()]);
    })
    .then(([res1, res2]) => {
      this.setState({
        newProduct: res1.products,
        discountProduct: res2.products
      })
    })
  }

3. hipce를 하면서 아쉬웠던 점

Resizing

스크롤 이벤트를 구현할 때 직접 컴포넌트의 위치를 scrollY로 찾아 기입했다. 아주 잘 작동하지만 단점은 모든 화면에서 정상 작동하지 않는 다는 것이다. 가령 아주 작거나 큰 모니터 혹은 비율이 다른 모니터로 옮겨보면 픽셀 값이 달라지기 때문에 원래의 의도와 똑같이 작동하지는 않는다. 그렇기 때문에 Resizing(사실 맞는 단어인지 모르겠다)을 통해 화면이 달라질 때마다 스크롤의 위치가 달라지게끔 조정을 해줘야 한다. 하지만 이번 프로젝트에서는 구현하지 못했다. 다음 스크롤 이벤트를 구현할 때 꼭 시도해보자. 여러 사이즈의 모니터에서 호환 가능한 스크롤 이벤트!!!

Component Life Cycle

라이프 사이클은 머리로는 이해가 가지만 아직도 에러가 아주 많이 나는 부분이다. 메인 슬라이더에서 그림을 클릭시 해당 제품의 정보를 보여주는 로직이 있다. 이때 종택님이 열심히 설명해주셨지만 결국 그 자리에서 이해하지 못하고 외워버렸던 사이클을 적어보도록 하자 ^_^

export default class Main extends Component {
  render() {
    return (
      <MainNewProduct newProduct = {this.state.newProduct} />
    )
  }
}
export default class MainNewProduct extends Component {
  render() {
    return (
      <div className="MainNewProduct">
        <MainNewProductSlider newProduct={this.props.newProduct} />
      </div>
    );
  }
}
export default class MainNewProductSlider extends Component {
  render() {
  cont { newIndex } = this.state;
  const { newProduct } = this.state;
  return (
    <div className="sectionProduct>
    //부모의 부모 컴포넌트에서 props를 넘겨받은 상황이다. 먼저 그 값이 트루인지를 물음표로 판단하고 있다. 최신 문법이라 조금 생소하지만 유용하게 쓰일 것 같다.
      {newProduct[newIndex]?.name}
    </div>
   )
  }
}

그때 바로 기록하지 않아서 기억이 조금 날라갔다. 반복 학습을 통해 꼭 이해하고 넘어가자. 현재 생각나는 것을 말해보면 자식 컴포넌트가 완성되고 나서 부모 컴포넌트가 불리게 된다. 그래서 자식 컴포넌트에서 props를 받아서 값을 띄울 때 undefined가 나오는 이유는 부모가 완성되기도 전에 자식이 그 값을 렌더했기 때문이다.

가독성 좋은 코드

처음으로 구매 플로우를 완성해보는 사이트를 만들었고 팀원끼리 서로의 작업을 이어받아 진행하는 경우도 있었다. 이때 가장 중요한 것은 가.독.성. 이제 더 이상 나 혼자 하는 작업은 거의 없을 것이다. 남을 배려하고 남의 입장에서 내 코드를 이해해보려 노력하고 또 노력하는 것이 정말 중요하다.

  • Distructuring
  • 함수와 함수 사이, scss의 클래스명 사이
  • 의미를 쉽게 파악할 수 있는 함수명, 변수명
  • 컴포넌트의 분리
  • 불필요한 반복을 피하도록 하자. 쓸데없이 긴 코드를 상대방으로 하여금 두통을 일으킨다.
profile
싱글벙글

0개의 댓글