첫번째 포스팅에서 화면 뼈대 구성까지 진행하였습니다.
큰 어려움은 없었는데요!
🐣이번에는 store를 만들어보고자 합니다🐣
슈퍼마켓 구현하기(2) 포스트는 상태관리를 위한 store를 만들고, 각각의 store들을 rootStore를 통해서 연결시켜주는 내용을 담고있습니다.
mobX 공식문서를 읽어보니, decorator는 ES standard가 아니라서 잘 안쓴다고 나와있더라구요! 그래서 makeObservable을 이용해서 annotation을 설정하도록 하겠습니다.
(저는 decorator가 더 귀엽고 아기자기한데.. 귀여운게 밥먹여주지는 않으니 😏)
src/stores/ProductStore.ts
import {makeObservable, action, observable, computed, toJS} from 'mobx';
export interface Product{
id: number;
name: string;
price: number;
choice: number;
}
export default class ProductStore{
constructor(){
makeObservable(this,{
productList: observable,
addProduct: action,
removeProduct: action,
getProducts: computed,
getProductsNum: computed,
})
}
productList: Product[] =[
{id:0, name:'매운새우깡', price:1800, choice:1},
{id:1, name:'콘쵸', price: 1200, choice: 1},
{id:2, name:'허니버터칩', price:1500, choice:1}
]
addProduct(newProduct: Product){
this.productList = [...this.productList, newProduct]
}
removeProduct(id: number){
this.productList.splice(id, 1)
}
get getProducts(){
return toJS(this.productList);
}
get getProductsNum(){
return toJS(this.productList.length)
}
}
src/srotes/BasketStore.ts
import {makeObservable, action, observable, computed, toJS} from 'mobx';
import {Product} from './ProductStore';
export default class BasketStore {
constructor(){
makeObservable(this,{
itemList: observable,
totalPrice: observable,
updateItem: action,
returnItem: action,
removeItem: action,
setTotalPrice: action,
getItems: computed,
getTotalPrice: computed,
})
}
itemList: Product[]=[];
totalPrice: number = 0;
updateItem(item: Product){
const found = this.getItems.findIndex((el)=>el.id === item.id);
if(found>=0) this.itemList[found].choice++;
else this.itemList = [...this.itemList, item];
this.setTotalPrice();
}
returnItem(id: number){
this.itemList = this.itemList.map((item)=>{
if(item.id === id) item.choice--;
return item;
})
this.setTotalPrice();
}
removeItem(id: number){
const idx = this.itemList.findIndex(el=>el.id===id);
this.itemList.splice(idx,1);
this.setTotalPrice();
}
setTotalPrice(){
this.totalPrice = this.itemList.reduce((acc: number, current: Product)=>{
return acc + (current.price * current.choice);
}, 0)
}
get getItems(){
return toJS(this.itemList);
}
get getTotalPrice(){
return toJS(this.totalPrice);
}
}
step1과 동일
1. rootStore생성✨
src/stores/rootStore.ts
import BasketStore from './BasketStore';
import ProductStore from './ProductStore';
export default class RootStore{
constructor(){
this.basketStore = new BasketStore(this);
this.productStore = new ProductStore(this);
}
basketStore: BasketStore;
productStore: ProductStore;
}
Store 인스턴스 생성시 꼭 this를 넣어줘야 rootStore를 통한 다른 store로 접근이 가능해집니다!!
2. Provider로 rootStore를 프로젝트에 적용✨
src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'mobx-react'
import RootStore from './stores/rootStore'
const rootStore = new RootStore();
ReactDOM.render(
<Provider {...rootStore}>
<App />
</Provider>
,
document.getElementById('root')
);
3. rootStore를 constructor argument로 지정✨
constructor의 argument로 rootStore를 받아줍니다!
src/stores/BasketStore.ts
...
import RootStore from './rootStore';
...
export default class BasketStore{
constructor(rootStore: RootStore){
...
}
...
}
src/stores/ProductStore.ts
...
import RootStore from './rootStore';
...
export default class ProductStore{
constructor(rootStore: RootStore){
...
}
...
}
✨ Spread-syntax
https://velog.io/@kwonh/ES6-%ED%8E%BC%EC%B9%A8%EC%97%B0%EC%82%B0%EC%9E%90%EC%A0%84%EA%B0%9C%EC%97%B0%EC%82%B0%EC%9E%90-Spread-Syntax-Spread-Operator
✨ JS스럽게 코드 쓰는 법
https://velog.io/@wooder2050/JS%EC%8A%A4%EB%9F%BD%EA%B2%8C-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C-%EC%93%B0%EA%B8%B0-%EA%BF%80%ED%8C%81
✨ 슈퍼마켓 구현하기
https://hyeok999.github.io/2020/04/16/mobx-hooks-market/
https://velog.io/@velopert/MobX-3-%EC%8B%AC%ED%99%94%EC%A0%81%EC%9D%B8-%EC%82%AC%EC%9A%A9-%EB%B0%8F-%EC%B5%9C%EC%A0%81%ED%99%94-%EB%B0%A9%EB%B2%95-tnjltay61n