본문 바로가기
Study/React

React Hooks + Mobx 예제 - 슈퍼마켓 구현하기 -

by 오늘만 사는 여자 2021. 4. 28.
728x90
반응형

Reference URL : hyeok999.github.io/2020/04/16/mobx-hooks-market/

 

React Hooks + Mobx 예제 - 슈퍼마켓 구현하기 -

React Hooks + Mobx 예제 - 슈퍼마켓 구현하기 -목차 소개 시작 데코레이터 설정 X 프로젝트 초기화 및 폴더 구조 카운터 만들기 new: src/stores/counter.js new: src/useStore.js edit: src/App.js new: src/components/Counter.j

hyeok999.github.io

 

소개

2019년에 들어서면서 React 측에서 Hooks를 소개했습니다. Hooks는 React 생태계에서 적지 않은 파생을 일으켰고 많은 코드들이 마이그레이션되었습니다.

오늘 소개할 예제는 기존의 velopert 님께서 작성하신 Mobx 슈퍼마켓 구현하기 를 Hooks 형태로 마이그레이션 하는 작업을 해보도록하겠습니다.

시작하기 전에 다음과 사항을 읽어주세요.

  1. 저는 주니어 개발자입니다. 미흡한 점이 많으니 잘못된 부분은 지적 부탁드립니다.
  2. Mobx는 정말 자유롭습니다. 기존 코드나 공식홈페이지에서 제공하는 코드와 양식이 다소 다를 수 있습니다.

 

우선, 저는 원래 React에서는 Hooks를 즐겨 사용하였고 상태 관련 라이브러리는 Redux + Redux Saga를 사용하였습니다.

이번에 Mobx를 공부하면서 Mobx에 대한 대부분의 레퍼런스들은 여전히 Class 기반의 데코레이터를 많이 사용하는 것을 확인하였고 레퍼런스 등록 날짜도 대부분이 2018년에서 19년 초였습니다… 😞

여러가지 강좌나 레퍼런스를 읽으며 Mobx를 사용하는 방법들을 익혔고 velopert님이 작성하신 Mobx 슈퍼마켓 구현하기를 Hooks와 Function형태로 변경해보도록 하겠습니다.

클래스의 형태와 쉽게 비교하기 위해서 velopert님이 작성하신 순서를 그대로 따라가도록 하겠습니다.

 

시작

$ npx create-react-app study
$ npm  i mobx mobx-react

데코레이터 설정 X 🙅‍♀️

JS 기준으로 기존 mobx의 데코레이터를 이용하기 위해서는 npm run eject를 해주고 설정해야만 했습니다. Hooks를 이용할 때에는 굳이 데코레이터를 이용하지 않겠습니다. 만약에 별도로 이용하고 싶으시면 다음 코드를 추가합니다. 제가 사용할 예제에서는 데코레이터를 이용하지 않습니다.

$ npm i @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators

 

VSC 기준 : VSC 환경설정 : CMD + , 누르고 TypeScript Decorators 검색

 

프로젝트 초기화 및 폴더 구조

시작하기에 앞서 프로젝트를 초기화하겠습니다.

src 폴더 내에 App.js  index.js를 제외한 모든 파일을 삭제합니다. 그 후 index.js  App.js의 파일을 다음처럼 수정합니다.

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
// src/App.js
import React from 'react';

function App() {
  return <div className="App"></div>;
}

export default App;

마지막으로 완성된 폴더구조와 화면은 다음과 같습니다.

카운터 만들기

new: src/stores/counter.js

추후에 market관련 데이터도 스토어로 만들 것이기 때문에 stores라는 폴더를 생성하고 내부에 counter 스토어를 만들어줍니다.

저는 데코레이터를 이용하지 않을 것이기 때문에 class가 아니라 객체 형태와 메소드로 작성하고 observable로 감싸줍니다.

 

new: src/useStore.js

stores 폴더에 생길 모든 스토어들을 한 곳을 통해서 불러들이게끔 하기 위해서 custom Hook을 다음과 같이 작성합니다.

import { counter } from './stores/counter';

const useStore = () => {
  return { counter };
};

export default useStore;

 

edit: src/App.js

앞으로 만들어진 Counter 컴포넌트를 추가하도록 하겠습니다.

import React from 'react';
import Counter from './components/Counter';

function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;

 

new: src/components/Counter.jsx

게속해서 컴포넌트가 많아질 것입니다. 따라서 components 폴더를 생성하고 안에 Counter.jsx파일을 생성합니다.

기존 class에서는 @나 decorate를 이용하고서 observer로 컴포넌트를 감싸주는 방식을 이용했었습니다.

mobx가 6.xxx 버전 이상으로 올라오게 됨에 따라 Hook관련 기능이 추가되었습니다. (그 전에는 mobx-react-lite 를 이용)

사용방법은 정말 간단합니다.

그냥 return 할 때 useObserver를 반환하고 실제 JSX코드는 콜백으로 넣어주시면 됩니다.

import React from 'react';
import { useObserver } from 'mobx-react';
import useStore from '../useStore';

const Counter = () => {
  const { counter } = useStore();

  const increase = () => {
    counter.increase();
  };

  const decrease = () => {
    counter.decrease();
  };

  return useObserver(() => (
    <div>
      <h1>{counter.number}</h1>
      <button onClick={increase}>+1</button>
      <button onClick={decrease}>-1</button>
    </div>
  ));
};

export default Counter;

 

슈퍼마켓 UI 구현하기

우선 기능을 구현하기 전에, 컴포넌트들의 유저인터페이스부터 만들어주겠습니다!

UI 부분은 velopert님과 거의 동일합니다. 더 정확한 소스를 보고 싶으시면 velopert.log를 참고해주세요. 아래의 코드는 전부 벨로퍼트님의 코드를 그대로 가져와서 작성한 것입니다.

 

new: src/components/SuperMarketTemplate.jsx

import React from 'react';
import './SuperMarketTemplate.css';

const SuperMarketTemplate = ({ items, basket }) => {
  return (
    <div className="SuperMarketTemplate">
      <div className="items-wrapper">
        <h2>상품</h2>
        {items}
      </div>
      <div className="basket-wrapper">
        <h2>장바구니</h2>
        {basket}
      </div>
    </div>
  );
};

export default SuperMarketTemplate;

 

/* src/components/SuperMarketTemplate.css */
.SuperMarketTemplate {
  width: 768px;
  display: flex;
  border: 1px solid black;
  margin-left: auto;
  margin-right: auto;
  margin-top: 3rem;
}

.SuperMarketTemplate h2 {
  margin-top: 0;
}

.SuperMarketTemplate>div {
  padding: 1rem;
  flex: 1;
}

.SuperMarketTemplate .items-wrapper {
  background: #f8f9fa;
}

 

SuperMarketTemplate 는 그냥 템플릿 형태의 컴포넌트로서 한쪽에는 상품을, 한쪽에는 장바구니를 props 로 받아와서 보여줍니다.

 

new: src/components/SuperMarket.jsx

import React from 'react';
import SuperMarketTemplate from './SuperMarketTemplate';


const SuperMarket = () => {
  return <SuperMarketTemplate items={null} basket={null} />;
};

export default SuperMarket;

SuperMarket 컴포넌트는 SuperMarketTemplate 안에, 나중에 우리가 만들 Basket 과 ShopItemList 를 전달해서 보여줄 것입니다. 지금은 아직 안만들었으니 null 만 넣어주세요.

그리고나서, SuperMarket 를 App 에서 보여주겠습니다.

 

edit: src/App.js

import React from "react";
import Counter from "./components/Counter";
import SuperMarket from "./components/SuperMarket";

function App() {
  return (
    <div>
      <Counter />
      <hr />
      <SuperMarket />m
    </div>
  );
}

export default App;

 

좌측 상품 구현

new: src/components/ShopItem.js

import React from "react";
import "./ShopItem.css";

const ShopItem = ({ name, price }) => {
  return (
    <div className="ShopItem">
      <h4>{name}</h4>
      <div>{price}원</div>
    </div>
  );
};

export default ShopItem;
/* src/components/ShopItem.css */
.ShopItem {
  background: white;
  border: 1px solid #495057;
  padding: 0.5rem;
  border-radius: 2px;
  cursor: pointer;
}

.ShopItem h4 {
  margin-top: 0;
  margin-bottom: 1rem;
}

.ShopItem:hover {
  background: #495057;
  color: white;
}

.ShopItem + .ShopItem {
  margin-top: 1rem;
}

 

new: src/components/ShopItemList.jsx

import React from "react";
import ShopItem from "./ShopItem";

const items = [
  { name: "생수", price: 850 },
  { name: "신라면", price: 1200 },
  { name: "포카칩", price: 850 },
  { name: "아이스크림", price: 500 },
];

const ShopItemList = () => {
  const itemList = items.map((item) => <ShopItem {...item} key={item.name} />);
  return <div>{itemList}</div>;
};

export default ShopItemList;

이렇게 만들어 주고 나서, ShopItemList 를 SuperMarket 에서 보여주겠습니다.

 

 

728x90
반응형

'Study > React' 카테고리의 다른 글

[React] JSX란?  (0) 2021.04.28
React-Hooks 예시  (0) 2021.04.28

댓글