VueJS | Stock-Trader Project Tutorial (2)

이 포스팅은 Max의 Vuejs 강좌 내용을 정리한 것이고, VueJS의 개념을 익히고 연습해보기 위한 튜토리얼을 다룬 글 입니다.


이번 포스팅에서는 프로젝트의 상태 관리를 위한 vuex 환경을 세팅하고 상태 변화에 따라 View의 변화를 확인 할 수 있도록 구현하고자 합니다.

1. Stock 컴포넌트 생성하기

  • 가장 먼저 아래 그림과 같이 UI를 구현합니다.
    • props: ['stock'] 는 상위 컴포넌트로 부터 데이타를 받아오기 위한 설정입니다. 그러면 현재 템플릿 안에서 와 같이 설정된 이름으로 변수를 설정 할 수 있습니다.
    • 부모 컴포넌트에서 데이타를 전달 할 때는 전달할이름="부모컴포넌트내부데이타"와 같이 부모 컴포넌트에서 자식 컴포넌트를 사용하는 태그 내에 속성으로 적용하면 됩니다.
    • 그리고 데이타를 전송하기 위해서 Buy 버튼에는 클릭을 했을 때 buyStock 메소드를 사용하도록 설정해줍니다.
    • 템플릿 내부의 디렉티브나 스크립트 부분에 사용하는 메소드 같은 기본적인 개념들은 VueJS에 아주 친절하게 설명되어 있으니 참고 하시기 바랍니다.

Stock Component
src/components/stocks/Stock.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<template>
<div class="col-md-4 col-sm-6">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">
{{ stock.name }} <!-- 상위 컴포넌트로 부터 전달 받은 props 데이타 -->
<small>(Price: {{ stock.price }} )</small>
</h3>
</div>
<div class="panel-body">
<div class="pull-left">
<input
type="number"
class="form-control"
placeholder="Quantity"
v-model.number="quantity"
>
</div>
<div class="pull-right">
<button
class="btn btn-success"
@click="buyStock"
:disabled="quantity <= 0 || !Number.isInteger(quantity)"
>Buy</button>
</div>
</div>
</div>
</div>
</template>

<script>
export default {
props: ['stock'],

data() {
return {
quantity: 0
}
},
methods: {
buyStock() {
const order = {
stockId: this.stock.id,
stockPrice: this.stock.price,
quantity: this.quantity,
};
console.log(order);
this.quantity = 0;
}
}
}
</script>
  • 이전 포스팅에서 stocks 폴더 내에는 Stocks.vue, Stock.vue 파일을 생성하였습니다. 위에서 구현한 Stock.vue 내용은 위 그림처럼 데이타에 따라 하나의 박스를 그려 줍니다. 그리고 Stocks.vue에서는 가지고 있는 데이타에 따라서 Stock.vue를 반복적으로 사용합니다.
    • 위에서 생성한 Stock.vue 파일을 import 해주고 components 에 사용할 이름을 설정해줍니다.
    • 컴포넌트 이름을 설정할때는 보통 <script> 부분에서 camelCase 방식으로 선언하면 <template> 부분에서 kebab-case 방식으로 해당 컴포넌트를 사용 할 수 있습니다.
    • 세팅된 컴포넌트는 data 에 있는 stocks 데이타에 따라 컴포넌트들을 출력해줍니다.
src/components/stocks/Stocks.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div>
<app-stock v-for="stock in stocks" :stock="stock"></app-stock>
</div>
</template>

<script>
import Stock from './Stock.vue';
export default {
data() {
return {
stocks: [
{ id: 1, name: 'BENZ', price: 200},
{ id: 2, name: 'AUDI', price: 150},
{ id: 3, name: 'HONDA', price: 180},
{ id: 4, name: 'LEXUS', price: 195}
]
}
},
components: {
appStock: Stock
}
}
</script>

2. Vuex 환경 세팅하기

1. vuex 모듈 설치 및 파일 생성

  • 먼저 npm install --save vuexvuex를 설치해줍니다.
  • 그리고 아래 파일 구조에 맞게 store 폴더 내에 파일들을 생성해줍니다.
  • 이 프로젝트에서 vuex 환경은 컴포넌트 단위 별로 modules 폴더에 분리해서 설정해주고 store.js 에 각각의 설정을 추가하여 사용합니다.
  • vuex 관련 개념들은 Vuex에 친절하게 잘 나와 있습니다. VueJS는 대부분 관련 문서들이 한글화 되어 있어 참 좋습니다. ^^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
src
├── data
│ └── stocks.js
├── components
│ ├── Header.vue
│ ├── Home.vue
│ ├── portfolio
│ │ ├── Portfolio.vue
│ │ └── Stock.vue
│ └── stocks
│ ├── Stock.vue
│ └── Stocks.vue
└── store
├── store.js
└── modules
├── stocks.js
└── portpolio.js

2. stocks.js 모듈 구현하기

  • 컴포넌트 단위 별로 분리하여 설정하기로 하였기 때문에 Stocks 관련 설정 먼저 해줍니다.
  • vuex를 구성하는 핵심 기능은 state, mutation, action, getter 입니다.
    • 각각에 대한 상세한 개념은 Vuex-State 를 참고해주세요.
  • 먼저 initStocks action을 사용 가능하도록 구현하기 위해 Stocks.vue 에서 배열 데이타를 컴포넌트에 직접 추가해서 사용했던 것을 별도 파일로 data 폴더에 분리시켜 가져오도록 하는 방식으로 데이타를 초기화 하는 기능을 구현합니다.
    • data 폴더는 임시로 사용하는 것이고, 나중에 삭제하셔도 됩니다. 다다음 포스팅 쯤에서 vue-resource를 활용해서 firebase를 활용한 DB와 통신하는 부분을 구현 할 것입니다.
    • buyStock, randomizeStocks action은 나중에 구현하겠습니다.
src/data/stocks.js
1
2
3
4
5
6
export default [
{ id: 1, name: 'BENZ', price: 200},
{ id: 2, name: 'AUDI', price: 150},
{ id: 3, name: 'HONDA', price: 180},
{ id: 4, name: 'LEXUS', price: 195}
];
src/store/modules/stocks.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import stocks from '../../data/stocks';

const state = {
stocks: []
};

const mutations = {
'SET_STOCKS' (state, stocks) {
state.stocks = stocks;
},
'RND_STOCKS' (state) {

}
};

const actions = {
buyStock: ({commit}, order) => {
commit();
},
initStocks: ({commit}) => {
commit('SET_STOCKS', stocks);
},
randomizeStocks: ({commit}) => {
commit('RND_STOCKS');
}
};

const getters = {
stocks: state => {
return state.stocks;
}
};

export default {
state,
mutations,
actions,
getters
}

3. store.js, main.js 설정 추가하기

  • store.js 에서 사용 할 모든 모듈들을 등록해서 사용합니다.
    • Vuex.Storemodules에 위에서 구현한 stocks 모듈을 등록해줍니다.
src/store/store.js
1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue';
import Vuex from 'vuex';

import stocks from './modules/stocks'

Vue.use(Vuex);

export default new Vuex.Store({
modules: {
stocks
}
});
  • store.jsmain.js에 등록하여 사용합니다.
src/main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Vue from 'vue';
import VueRouter from 'vue-router';

import App from './App.vue';
import { routes } from './routes';
import store from './store/store'; // store.js를 import 합니다.

Vue.use(VueRouter);

const router = new VueRouter({
mode: 'history',
routes
});

new Vue({
el: '#app',
router,
store, // store를 등록해줍니다.
render: h => h(App)

4. store 사용하기

  • main.jsstore를 등록하였기 때문에 이제 어떤 컴포넌트에서든지 별도의 설정 없이 store를 사용 할 수 있습니다.
    • 컴포넌트 내에서 store 에 접근 하는 방법은 this.$store 입니다.
    • 그리고 기능에 맞는 메소드를 사용하여 등록된 기능을 활용합니다.
    • action은 this.$store.dispatch('action이름') 과 같이 사용하면 됩니다.
src/App.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div class="container">
<app-header></app-header>
<div class="row">
<div class="col-md-12">
<router-view></router-view>
</div>
</div>
</div>
</template>

<script>
import Header from './components/Header.vue';
export default {
components: {
'appHeader': Header
},
created() {
this.$store.dispatch('initStocks'); // store에 등록된 action을 사용합니다.
}
}
</script>

<style>
body {
padding: 30px;
}
</style>
  • App.vue에서 initStocks action 으로 stocks state를 초기화 해주었습니다.
  • Stocks.vue에서 store에 등록된 state를 사용하기 위해 data에 있던 stocks는 제거합니다.
    • 등록되어 있는 state의 값을 값을 가져오기 위해 getter를 등록하고 사용해주어야 합니다.
    • 컴포넌트 내에서 getter를 사용하는 방밥은 this.$store.getters.메소드이름 입니다.
  • 자식 컴포넌트로 props를 전달하는 부분에서 본인이 이름이 햇갈려서 props의 이름을 propStock 으로 변경하였습니다.
    • Stock.vue 에서도 전달 받는 props의 이름을 props: ['propStock'] 과 같이 변경해주고 관련된 변수들을 모두 변경해주셔야 합니다.
src/components/stocks/Stocks.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<app-stock v-for="stock in stocks" :propStock="stock"></app-stock>
</div>
</template>

<script>
import Stock from './Stock.vue';
export default {
components: {
appStock: Stock
},
computed: {
stocks() {
return this.$store.getters.stocks; // getter로 현재 state 값을 가져옵니다.
}
}
}
</script>

모두 완료되었다면 아래와 같이 data/stocks.js에 있는 데이타에 따라 Stock 컴포넌트들이 출력 될 것입니다.
git clone 으로 프로젝트를 시작하셨다면 git checkout step04 로 이번 포스팅의 마지막 결과물을 확인 하실 수 있습니다.
다음 포스팅에서는 Portfolio 컴포넌트의 상태 설정을 추가하고 Stocks 컴포넌트와 함께 state의 변화에 따라 View 가 갱신 되는 부분까지 구현해보겠습니다.
한번에 해보려고 했더니 너무 길어질 것 같아서 여기서 끊고 추후에 진행해보려 합니다. ㅎㅎ 별거 없는 내용인데도 손이 느려서 시간이 꽤 걸리네요.
필요하신 부분이나 보완할 점이 있다면 댓글로 의견 남겨주시기 바랍니다. 감사합니다.

STEP04


- 끝 -

Share Comments