카테고리 없음

vue3 + vuex + mitt + watch Composition API 사용법

소행성왕자 2023. 1. 16. 13:53

vue3 의 Composition API  <script setup> 을 이용하여 store 와 mitt  그리고 watch 에 대해서 사용법을 알아보도록 하겠습니다.

vuex / mitt 설치는 아래 링크를 참고하세요

https://trytoso.tistory.com/1628

 

vue3 에서 vuex 사용법과 mitt 컴포넌트끼리의 통신 하는 방법

vue3 에서 vuex 를 이용하여 전역으로 데이터를 관리할수 있는 store 사용법과 컴포넌트 끼리 통신할수 있는 mitt 사용법을 알아보도록 합니다. vue3의 문법은 가 아닌 를 이용하는 Composition API 사용법

trytoso.tistory.com

 

컴포넌트 구조

컴포넌트는 n-test.vue 와 W1101.vue 두개의 컴포넌트를 사용하겠습니다.

 

n-test.vue 

html 부분을 아래와 같습니다.

<template>
    <div>
        <h1>n-test.vue</h1>
        <button @click="logout" v-if="loginStatus">Logout</button>
        <button @click="login" v-else>Login</button>
        <pre>loginStatus: {{ loginStatus }}</pre>
        <pre>id: {{ id }}</pre>
    </div>
</template>

 

Composition API 를 사용하기 위해 기본적인 모듈을 적재합니다.

추가할 사항이 있으면 추가하시면 됩니다.

<script setup>

import { 
    ref, 
    computed,
    onMounted,
    watch,
    inject,
} from 'vue';
import { useStore } from 'vuex';


const store = useStore();
const bus = inject('emitter');
...

 

console.log 를 편하게 하기 위해 함수 dd() 를 하나 만들었습니다.

const dd = (data, header = false) => {
    let now = new Date();
    let h = now.getHours();
    let m = now.getMinutes();
    let s = now.getSeconds();
    let ms = now.getMilliseconds();

    console.log(`>>>>>: ${h}:${m}:${s} ${ms}`)
    if(header) {
        console.log(`-------${header}------`);
        console.log(data);
    }
    else console.log(data);
};

 

1. vuex 의 store 사용법

onMounted : 라이프 사이클 훅인 mounted 의 setup 내부에서 호출 하는 방법입니다.

component 로딩 되었으면 afterLogin() 할수 를 호출합니다.

onMounted(_=>{
    dd('on Mounted');
    afterLogin();   // afterLogin() 함수 호출
});

 

afterLogin 함수는 어떠한 필요 정보를 받아온후 store 에 저장하는 기능을 합니다.

afterLogin 할수가 호울되면 dispatch 을 이용하여 store의 actions 의 afterLogin 함수가 호출됩니다.

 

const obj2 = { al: { id: 'naya', email: 'verylove@naver.com'} };
const afterLogin =_=> {
    store.dispatch('afterLogin', obj2);
    dd(store.getters.afterLogin, 'afterLogin')
}

 

actions 의 호출된 함수(afterLogin) 는 commit 을 이용하여  mutations 의   SET_AFTER_LOGIN 함수를 호출하여

해당 값(val) 을 실제 store 에 저장합니다.

 

store/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    afterLogin: null,
  },
  getters: {
    afterLogin: state => state.afterLogin,
  },
  mutations: {
    SET_AFTER_LOGIN(state, val) {
      state.afterLogin = val;
    },
  },
  actions: {
    afterLogin( {commit}, { al }) {
      commit('SET_AFTER_LOGIN', al);
    },
  },
  modules: {
  }
})

 

저장된 store 의 값을 보려면 아래와 같이 하면 됩니다.

dd(store.getters.afterLogin, 'afterLogin')

 

2. watch 사용 방법 

store 객체의 afterLogin 에 어떠한 정보가 들어오거나 수정되면 sendTr1() 할수를 호출하고 싶습니다.

이와 같을때 아래와 같이 하면 됩니다.

watch(_=>store.getters.afterLogin, function() {
    dd('afterLogin value changes detected');    
    // afterLogin 받아왔으니 sendTr1() 호출후 nowCrncy 저장 
    sendTr1();
}, {deep:true} );  // 객체 변경을 감지하기 위해

 

그러면 sendTr1() 함수가 호출되고 n-test__W1101 이름을 가지는 bus 로 다른 component 에서 불러올수 있습니다.

const sendTr1 =_=>{
    dd('sendTr1() start');

    const tr = {};
    tr.trName = 'W1101';
    tr.id = store.getters.afterLogin.id;

    /*
        1. emitter 버스 보냄
    */
    bus.emit('n-test__W1101',tr);

}

 

W1101.vue 

n-test__W1101 의 이름을 가지는 버스를 찾아서 실행합니다.

여기서는 console.log 찍고 nowCrncy 함수를 이용하여 store 저장소의 nowCrncy 저장소에 저장합니다.

bus.on('n-test__W1101', (val) => {   
    dd(val, 'n-test__W1101'); 
    
    // nowCrncy 저장소에 저장
    const res = { nc: {id:'W6112S01', date:'2023.01.16', time:'11:05:37'} }
    const nowCrncy =_=> {
        store.dispatch('nowCrncy', res);
        dd(store.getters.nowCrncy, 'nowCrncy')
    }
    nowCrncy(); 
});

 

여기서 저장소의 nowCrncy 에 값이 저장되거나 변경되는 watch를 만들어보겠습니다.

watch 는 n-test 파일에서 확인해보겠습니다.

n-test.vue 

watch(_=>store.getters.nowCrncy, function() {
    dd('nowCrncy value changes detected');    
});

 

실행결과

 

전체소스

App.vue

<script setup>
import { ref } from 'vue';

import tradingviewVue from './components/tradingview.vue'
import nTestVue from './components/n-test.vue';
import W1101Vue from './components/W1101.vue';

</script>

<template>
  
  
  <nTestVue ref="nTestVue"></nTestVue>
  <W1101Vue ref="W1101Vue"></W1101Vue>
  

</template>
<style scoped>

</style>

main.js

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import store from './store'
import mitt from 'mitt'
const emitter = mitt();


/*
createApp(App)
    .use(store)
    .use(mitt)
    .mount('#app')
*/

const coforwardUi = createApp(App);

coforwardUi.provide('emitter', emitter)
coforwardUi.use(store);
coforwardUi.mount('#app');

/*

import { createApp, } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import jQuery from 'jquery'

import currencyFormat from './js/currencyFormat'

import { socketWorker,wsObj } from './js/socketWorker'

//Vue App의 구성
var coForwarVueUi=createApp(App);
coForwarVueUi.use(store);
coForwarVueUi.use(router);
coForwarVueUi.use(currencyFormat);

coForwarVueUi.mount('#app');


window.vueUi=coForwarVueUi;

global.$ = jQuery




//소켓워커 초기화 실행
window.coForwardSocket = socketWorker;
// window.coForwardSocket.init();

//==== 테스트 영역 ======//
// '636f466f7277617264'

// let utf8='636f466f727761726420ed959ceab880';
// let euckr='636f466f727761726420c7d1b1db'

// let header=socketWorker.headerInfo('length'); 
// console.log(header);
//==== 테스트 영역 끝 ======//


//쉐어드워커와 소켓포트를 전역으로 등록
coForwarVueUi.config.globalProperties.socketWorker=socketWorker;
coForwarVueUi.config.globalProperties.wsObj=wsObj;

*/

store/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    afterLogin: null,
    nowCrncy: null,
    user : null,
  },
  getters: {
    afterLogin: state => state.afterLogin,
    nowCrncy: state => state.nowCrncy,
    loginStatus: state => !!state.user,
  },
  mutations: {
    SET_AFTER_LOGIN(state, val) {
      state.afterLogin = val;
    },
    SET_NOW_CRNCY(state, val) {
      state.nowCrncy = val;
    },
    SET_USER(state, user) {
      state.user = user;
    }
  },
  actions: {
    afterLogin( {commit}, { al }) {
      commit('SET_AFTER_LOGIN', al);
    },
    nowCrncy( {commit}, {nc} ) {
      commit('SET_NOW_CRNCY', nc);
    },
    login( {commit}, { user }) {
      commit('SET_USER', user);
    },
    logout({commit}) {
      commit('SET_USER', null);
    }

  },
  modules: {
  }
})

n-test.vue

<script setup>

import { 
    ref, 
    computed,
    onMounted,
    watch,
    inject,
} from 'vue';
import { useStore } from 'vuex';


const store = useStore();
const bus = inject('emitter');

let id = ref('');

const dd = (data, header = false) => {
    let now = new Date();
    let h = now.getHours();
    let m = now.getMinutes();
    let s = now.getSeconds();
    let ms = now.getMilliseconds();

    console.log(`>>>>>: ${h}:${m}:${s} ${ms}`)
    if(header) {
        console.log(`-------${header}------`);
        console.log(data);
    }
    else console.log(data);
};

const obj = { user: { email: 'john@gmail.com' }};
const login = _ => store.dispatch('login', obj );
const logout = _ => store.dispatch('logout');
const loginStatus = computed(_=>store.getters.loginStatus);

const obj2 = { al: { id: 'naya', email: 'verylove@naver.com'} };
const afterLogin =_=> {
    store.dispatch('afterLogin', obj2);
    dd(store.getters.afterLogin, 'afterLogin')
}


const sendTr1 =_=>{
    dd('sendTr1() start');

    const tr = {};
    tr.trName = 'W1101';
    tr.id = store.getters.afterLogin.id;

    /*
        1. emitter 버스 보냄
    */
    bus.emit('n-test__W1101',tr);

}


watch(_=>store.getters.afterLogin, function() {
    dd('afterLogin value changes detected');    
    // afterLogin 받아왔으니 sendTr1() 호출후 nowCrncy 저장 
    sendTr1();
});

watch(_=>store.getters.nowCrncy, function() {
    dd('nowCrncy value changes detected');    
    id.value = store.getters.nowCrncy.id;
}, {deep:true}); // 객체의 값 변경을 감지하기 위해

onMounted(_=>{
    dd('on Mounted');
    afterLogin();   // afterLogin() 함수 호출
});

</script>

<template>
    <div>
        <h1>n-test.vue</h1>
        <button @click="logout" v-if="loginStatus">Logout</button>
        <button @click="login" v-else>Login</button>
        <pre>loginStatus: {{ loginStatus }}</pre>
        <pre>id: {{ id }}</pre>
    </div>
</template>

<style>
</style>

W1101.vue

<template>

</template>

<script setup>
import { 
    ref, 
    computed,
    onMounted,
    watch,
    inject,
} from 'vue';
import { useStore } from 'vuex';

const store = useStore();
const bus = inject('emitter');

const dd = (data, header = false) => {
    if(header) {
        console.log(`-------${header}------`);
        console.log(data);
    }
    else console.log(data);
};

bus.on('n-test__W1101', (val) => {   
    dd(val, 'n-test__W1101'); 
    
    // nowCrncy 저장소에 저장
    const res = { nc: {id:'W6112S01', date:'2023.01.16', time:'11:05:37'} }
    const nowCrncy =_=> {
        store.dispatch('nowCrncy', res);
        dd(store.getters.nowCrncy, 'nowCrncy')
    }
    nowCrncy(); 
});

</script>

<style>
</style>

 

함수가 많아질경우 코드 지저분해질것 같아 정리1

n-test.vue

<script setup>

import { 
    ref, 
    computed,
    onMounted,
    watch,
    inject,
} from 'vue';
import { useStore } from 'vuex';

const store = useStore();
const bus = inject('emitter');

const Dt = class {
    constructor() {
        this._now = new Date();
    }
    getY() {}
    getM() {}
    getD() {}
    getH() { return this._now.getHours(); }
    getM() { return this._now.getMinutes(); }
    getS() { return this._now.getSeconds(); }
    getMS() { return this._now.getMilliseconds(); }
}

const dd = (data, header = false) => {
    const dt = new Dt();
    console.log(`>>>>>: ${dt.getH()}:${dt.getM()}:${dt.getS()} ${dt.getMS()}`)
    if(header) {
        console.log(`-----${header}----`);
        console.log(data);
    }
    else console.log(data);
};

const obj = { user: { email: 'john@gmail.com' }};
const login = _ => store.dispatch('login', obj );
const logout = _ => store.dispatch('logout');
const loginStatus = computed(_=>store.getters.loginStatus);


let id = ref('');
const AfterLogin = class {
    constructor(obj) {
        this._obj = obj;
    }
    async fetch(url) {
        const res = await fetch(url, {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
            },
        });

        return  await res.json();
    }
    setStore() {
        store.dispatch('afterLogin', this._obj);
    }
    getStore() {
        id.value = store.getters.afterLogin.id;
        return store.getters.afterLogin;
    }
}




const sendTr1 =_=>{
    dd('sendTr1() start');

    const tr = {};
    tr.trName = 'W1101';
    tr.id = store.getters.afterLogin.id;

    /*
        1. emitter 버스 보냄
    */
    bus.emit('n-test__W1101',tr);

}

const change = _=> {
    dd('change')
    const res = { nc: {id:'W11zz', date:'2023.01.16', time:'13:05:37'} }
    const nowCrncy =_=> {
        store.dispatch('nowCrncy', res);
        dd(store.getters.nowCrncy, 'nowCrncy 222')
    }

    nowCrncy();
}


//------- watch start --------------------//
watch(_=>store.getters.afterLogin, _=> {
    dd('afterLogin value changes detected');    
    // afterLogin 받아왔으니 sendTr1() 호출후 nowCrncy 저장 
    sendTr1();
});

watch(_=>store.getters.nowCrncy, _=> {
    const dt = new Dt();
    dd('nowCrncy value changes detected');  
    dd(store.getters.nowCrncy, `nowCrncy_${dt.getM()}:${dt.getS()} ${dt.getMS()}`);
    id.value = store.getters.nowCrncy.id;
}, {deep:true});


//--------- process layer start ------------//
const afterLoginProc = async()=>{
    const obj = { al: { id: 'naya', email: 'verylove@naver.com'} };
    const af = new AfterLogin(obj);
    const json = await af.fetch('https://reqbin.com/echo/get/json');
    dd(json, 'fetch json 11')
    af.setStore();
    dd(af.getStore(), 'afterLogin 111');
}


//----------- life cycle start --------//
onMounted(_=>{
    dd('on Mounted');
    afterLoginProc();

    setTimeout(_=>{
        change();
    },5000)
});




</script>

<template>
    <div>
        <h1>n-test.vue</h1>
        <button @click="logout" v-if="loginStatus">Logout</button>
        <button @click="login" v-else>Login</button>
        <pre>loginStatus: {{ loginStatus }}</pre>
        <pre>id: {{ id }}</pre>
    </div>
</template>

<style>
</style>