vue.js 인프런 학습을 위한 강의와 책

Vuex 적용개요


현재 파일트리 상황

📦src
 ┣ 📂api
 ┃ ┗ 📜index.js
 ┣ 📂assets
 ┃ ┗ 📜logo.png
 ┣ 📂components
 ┃ ┣ 📜app.js
 ┃ ┣ 📜HelloWorld.vue
 ┃ ┗ 📜ToolBar.vue
 ┣ 📂routes
 ┃ ┗ 📜index.js
 ┣ 📂views
 ┃ ┣ 📜AskView.vue
 ┃ ┣ 📜JobsView.vue
 ┃ ┗ 📜NewsView.vue
 ┣ 📜App.vue
 ┣ 📜main.js
 ┗ 📜vue.config.js


vuex 설치

$ npm i vuex

src/ store/ index.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
    news: [],
  },
});

상태관리도 재사용성,관리을 위해 src/main.js 에서 적는게 아닌 src/ store/ index.js파일을 생성하고 import, use, 등록하고 new Vuex.Store({})export 한다.

src/ main.js

import Vue from "vue";
import App from "./App.vue";
import { router } from "./routes/index.js"; 
import { store } from "./store/index.js"; // <== 이렇게 코드를 추가한다.

Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App),
  router,
  **store,**
}).$mount("#app");




state: {
    news: [],
  },

State

  • state는 쉽게 말하면 프로젝트에서 공통으로 사용할 변수를 정의.
  • 프로젝트 내의 모든 곳에서 참조 및 사용이 가능.
  • state를 통해 각 컴포넌트에서 동일한 값을 사용할 수 있다.

출처:

https://uxgjs.tistory.com/149

[UX 공작소]



mutations: {
    SET_NEWS(state, news) {
      state.news = news;
    },
  },

Mutations

  • Mutations의 주요 목적은 state를 변경시키는 역활. (Mutations을 통해서만 state를 변경해야 함)
  • 비동기 처리가 아니라 동기처리. 위의 함수가 실행되고 종료된 후 그 다음 아래의 함수가 실행된다.
  • commit('함수명', '전달인자')으로 실행 시킬 수 있다.
  • mutations 내에 함수 형태로 작성.

출처:

https://uxgjs.tistory.com/149

[UX 공작소]



actions: {
    FETCH_NEWS(context) {
      fetchNewsList()
        .then((response) => {
          console.log(response.data);
          context.commit("SET_NEWS", response.data);
          // state.news = response.data;
        })
        .catch((error) => {
          console.log(error);
        });
    },
  },

Actions

  • Actions의 주요 목적은 Mutations를 실행시키는 역활을 합니다. Mutations이 실행되면 state도 변경이 되겠지요.
  • 동기 처리가 아니라 비동기처리를 합니다. 순서에 상관없이 먼저 종료된 함수의 피드백을 받아 후속 처리를 하게 됩니다.
  • dispatch('함수명', '전달인자')으로 실행 시킬 수 있습니다. ex) dispatch('함수명', '전달인자', {root:true})
  • actions 내에 함수 형태로 작성합니다.
  • 비동기 처리이기 때문에 콜백함수로 주로 작성합니다.

출처:

https://uxgjs.tistory.com/149

[UX 공작소]





State, Mutations, Actions 적용순서

src / view / JobsView.vue

<template>
  <div>
    <div v-for="job in **this.$store.state.jobs**" v-bind:key="job.id">
      {{ job.title }} // jobs를 this.$store.state.jobs로 전환
    </div>
  </div>
</template>

<script>
// import { fetchJobsList } from "../api/index.js";
// 강의에선 있어도 잘 돌아가나 지금 이시점에서 이 코드를 그냥 놔두면 오류를 일으킨다.

export default {

  // data() {
  //   return {
  //     jobs: [],
  //   };
  // },

  created() {
    this.$store.dispatch("FETCH_JOBS_LIST");
    // "this.$store.dispatch('xxx')" 이 코드는 
    // src/store/index.js에 상태를 넘길수있게 해준다.

    // fetchJobsList()
    //   .then((response) => (vm.jobs = response.data))
    //   .catch((error) => console.log(error));

  },
};
</script>

<style></style>
  1. jobsthis.$store.state.jobs로 수정한다. 그래야 로직을 끝마친 데이터 내용이 HTML에 표시된다.
  2. $store에서 처리하기 때문인지 import { fetchJobsList }...는 여기서 지우고 dispatch를 추가한다. $store로 넘길 이름을 여기서 정해 기입한다.
  3. fetchJobsList()data() 의 코드내용은 지운다. 상태관리하는 $store에서 다루기 때문이다.


import Vue from "vue";
import Vuex from "vuex";
import { fetchNewsList, fetchAskList, fetchJobsList } from "@/api/index.js"; // ✳1

Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
   ...

    jobs: [],  // ✳4
  },
  mutations: {  
    ...
 
    SET_JOBS(state, jobs) {  // ✳3
      state.jobs = jobs;
    },
  },
  actions: {
   ...


    FETCH_JOBS_LIST(context) {
      fetchJobsList()  // ✳2
        .then((response) => {
          console.log(response.data);
          context.commit("SET_JOBS", response.data);
        })
        .catch((error) => {
          console.log(error);
        });
    },
  },
});
  1. api주소를 쓸 수있게 { fetchNewsList, fetchAskList, fetchJobsList }import 한다.
  2. fetchJobsList() 관련된 상태관리동작 코드를 추가한다. mutations 에게 작업을 넘겨하 하기 때문에 context.commit로 함수명과 인수를 기입한다.
  3. mutations: {} 내부에 SET_JOBS함수를 기입... state: {}에 넘길려면 인수를 state.jobs에 대입한다.
  4. state에 들어간 jobs: []src / view / JobsView.vue에 있던 jobs: []와 동일한 역활을 한다.


v-for문의 경로이름 줄이기 (mapState, mapGetters)

<template>
  <div>
    <div v-for="job in this.$store.state.jobs" v-bind:key="job.id">
      {{ job.title }} 
    </div>
  </div>
</template>

template의 v-for문을 보면 경로를 표현하기 때문에 제법길다.

만약에 실무에서 이런저런 추가 업데이트를 할 시에 경로이름은 더 복잡해질수도 있다.

경로이름을 줄이기위해서 mapState, mapGetters를 활용 할 수도 있다.

src / store / index.js

.
.
.

export const store = new Vuex.Store({
  state: {
    news: [],
    jobs: [],
    ask: [],
  },
  getters: {
    fetchedAsk(state) {
      return state.ask;
    },
  },
.
.
.

getters:를 추가. fetchedAsk는 v-for문에 쓸 이름이다.

src / view / AskView.vue

<template>
  <div>
    <div v-for="item in fetchedAsk" v-bind:key="item.id">
      {{ item.title }}
    </div>
  </div>
</template>

<script>
// import { mapState, mapGetters } from "vuex";
import { mapGetters } from "vuex";

export default {
  computed: {
    ...mapGetters(["fetchedAsk"]),

    // #2
    // ...mapState({
    //   ask: (state) => state.ask,
    // }),

    // #1
    // ask() {
    //   return this.$store.state.ask;
    // }
  },
  created() {
    this.$store.dispatch("FETCH_ASK_LIST");
  },
};
</script>

<style></style>

mapGetters를 활용하기 위해 여기서 import하고 computed 한다.

모든 item에 적용을 위해 Spread Operator (스프레드 연산자)를 .이용하고 {}가 아닌 []같은 배열로 바꾸면 객체 리터럴를 활용해 변수명 fetchedAsk을 그대로 쓸 수있다.

다만 강좌에서는 import { mapState, mapGetters } from "vuex"이렇게 import를 하는데

지금 시점에서 이 코드 그대로 쓰면 오류가 일어난다. mapGetters만 쓴다면 mapState을 지워야 해결된다.



import, export default를 활용하는 모듈화

한파일에 코드가 길어질 시에 그 파일을 기준으로 가지치기 하듯이 분리하는 방법이다.

actions: {
//////////////////// 여기서...
    FETCH_NEWS_LIST({ commit }) {
      fetchNewsList()
        .then(({ data }) => {
          commit("SET_NEWS", data);
        })
        .catch((error) => {
          console.log(error);
        });
    },
    FETCH_ASK_LIST({ commit }) {
      fetchAskList()
        .then(({ data }) => {
          commit("SET_ASK", data);
        })
        .catch((error) => {
          console.log(error);
        });
    },
    FETCH_JOBS_LIST({ commit }) {
      fetchJobsList()
        .then(({ data }) => {
          commit("SET_JOBS", data);
        })
        .catch((error) => {
          console.log(error);
        });
    },
////////////////////////////// 여기까지의 코드를 복사한다.
  },

이렇게 있을 때 actions: {} 겍체의 내용들을 복사해서....


import { fetchNewsList, fetchAskList, fetchJobsList } <from "@/api/index.js";

export default {
  FETCH_NEWS_LIST({ commit }) {
    fetchNewsList()
      .then(({ data }) => {
        commit("SET_NEWS", data);
      })
      .catch((error) => {
        console.log(error);
      });
  },
  FETCH_ASK_LIST({ commit }) {
    fetchAskList()
      .then(({ data }) => {
        commit("SET_ASK", data);
      })
      .catch((error) => {
        console.log(error);
      });
  },
  FETCH_JOBS_LIST({ commit }) {
    fetchJobsList()
      .then(({ data }) => {
        commit("SET_JOBS", data);
      })
      .catch((error) => {
        console.log(error);
      });
  },
};

같은 디렉토리 안에서 별도의 파일을 만든후 export default {} 안에 전부 붙어넣기를 한다.

해당코드 중에서 fetchNewsList(), fetchAskList(), fetchJobsList() 처럼 import 가 필용한 코드면 import { fetchNewsList, fetchAskList, fetchJobsList } from "@/api/index.js";처럼 이것 역시 가져와 붙인다.



import Vue from "vue";
import Vuex from "vuex";
import mutations from "./mutation.js";
import actions from "./actions";

Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
    news: [],
    jobs: [],
    ask: [],
  },
  getters: {
    fetchedAsk(state) {
      return state.ask;
    },
    fetchedJobs(state) {
      return state.jobs;
    },
    fetchedNews(state) {
      return state.news;
    },
  },
  mutations,
  // actions: actions,
     actions,

});

기존 actions 코드를 지우고 import actions from "./actions"로 만든 파일을 연결

export const store = new Vuex.Store({})의 겍체안에 actions: actions, 로 연결한다.

그런데 이렇게 변수명과 값이 같으면 actions,처럼 축약이 가능하다.



여기까지의 대략 파일구조들

📜App.vue
┗📜main.js --> 📜ToolBar.vue
📂routes
┗ 📜index.js
┣ —— 📂views
┃ ┣ 📜AskView.vue
┃ ┣ 📜JobsView.vue
┃ ┗ 📜NewsView.vue
┗ 📂store
┗📜index.js
┣ 📜actions.js
┗ 📜mutation.js

profile
어떤 문제든 파악 할 수 있으며 해결책을 찾을 수 있는 개발능력을 꿈꾸고 있습니다.

0개의 댓글