본문 바로가기
Dev/Vue.js

[Vue.js] Hacker News - 라우터 실전

by dev_jsk 2020. 9. 21.
728x90
반응형

동적 라우트 매칭(Dynamic Route Matching)

주어진 패턴을 가진 라우터를 동일한 컴포넌트에 매핑할 때 동적 세그먼트를 사용하는 것

const User = {
  template: '<div>User</div>'
}

const router = new VueRouter({
  routes: [
    // 동적 세그먼트는 콜론으로 시작
    { path: '/user/:id', component: User }
  ]
})

이 경우 /user/kim/user/park 은 같은 경로에 매핑된다.

 

동적 세그먼트는 콜론:으로 표시하고 라우트가 일치하면 동적 세그먼트의 값은 모든 컴포넌트에서this.$route.params로 표시된다.

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

 

동일한 라우트에 여러 동적 세그먼트를 가질 수 있으며 $route.params의 해당 필드에 매핑된다.

/user/kim/gender/male => { username:'kim', gender:'male' }

UserView 구현

1. src/routers/index.jsUserView.vue 라우터 연결

import Vue from "vue";
import VueRouter from "vue-router";

import UserView from "../views/UserView.vue";

Vue.use(VueRouter);

export const router = new VueRouter({
  mode: "history",
  routes: [
    {
      // 파라미터 변수 연결 시 : 이용
      path: "/user/:id",
      component: UserView,
    },
  ],
});

2. src/store/index.jsstate 속성 값 추가

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

3. src/api/index.js에 User정보 받아오는 API 설정

import axios from 'axios';

const config = {
  baseUrl: "https://api.hnpwa.com/v0/",
};

function fetchUserInfo(username) {
    return axios.get(`${config.baseUrl}user/${username}.json`);
}

export { fetchUserInfo };

4. src/store/actions.js에 API에서 받아온 정보 처리 설정

import { fetchUserInfo } from "../api/index.js";

export default {
  FETCH_USER({ commit }, name) {
    fetchUserInfo(name)
      .then(({ data }) => {
        commit('SET_USER', data);
      })
      .catch((error) => {
        console.log(error);
      })
  }
};

5. src/store/mutations.js에 User정보 세팅하는 함수 설정

export default {
  SET_USER(state, user) {
    state.user = user;
  }
};

6. UserView.vue 수정

<template>
  <div>
    <!-- 데이터 뿌려주기 -->
    <p>name : {{ userInfo.id }}</p>
    <p>karma : {{ userInfo.karma }}</p>
    <p>created : {{ userInfo.created }}</p>
  </div>
</template>

<script>
export default {
  // 연산식 이용하여 store 변수 간편화
  computed: {
    userInfo() {
      return this.$store.state.user;
    },
  },
  // API 호출
  created() {
    const userName = this.$route.params.id;
    this.$store.dispatch("FETCH_USER", userName);
  },
};
</script>

<style>
</style>

결과

ItemView 구현

1. src/routers/index.jsItemView.vue 라우터 연결

import Vue from "vue";
import VueRouter from "vue-router";

import ItemView from "../views/ItemView.vue";

Vue.use(VueRouter);

export const router = new VueRouter({
  mode: "history",
  routes: [
    {
      // 파라미터 변수 연결 시 : 이용
      path: "/item/:id",
      component: ItemView,
    },
  ],
});

2. src/store/index.jsstate 속성 값 추가

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

3. src/api/index.js에 Item정보 받아오는 API 설정

import axios from 'axios';

const config = {
  baseUrl: "https://api.hnpwa.com/v0/",
};

function fetchCommentItem(id) {
    return axios.get(`${config.baseUrl}item/${id}.json`);
}

export { fetchCommentItem };

4. src/store/actions.js에 API에서 받아온 정보 처리 설정

import { fetchCommentItem } from "../api/index.js";

export default {
  FETCH_ITEM({ commit }, id) {
    fetchCommentItem(id)
      .then(({ data }) => {
        commit('SET_ITEM', data);
      })
      .catch((error) => {
        console.log(error);
      })
  }
};

5. src/store/mutations.js에 Item정보 세팅하는 함수 설정

export default {
  SET_ITEM(state, item) {
    state.item = item;
  }
};

6. ItemView.vue 수정

<template>
  <div>
    <!-- 질문 상세 정보 -->
    <section>
      <div class="user-container">
        <div>
          // Font Awesome User Icon
          <i class="fas fa-user"></i>
        </div>
        <div class="user-description">
          // User 상세 연결
          <router-link :to="`/user/${fetchedItem.user}`">{{ fetchedItem.user }}</router-link>
          <div class="time">{{ fetchedItem.time_ago }}</div>
        </div>
      </div>
      <h2>{{ fetchedItem.title }}</h2>
    </section>
    <!-- 질문 내용 -->
    <section>
      <div v-html="fetchedItem.content"></div>
    </section>
  </div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
  computed: {
    ...mapGetters(["fetchedItem"]),
  },
  created() {
    const itemId = this.$route.params.id;
    this.$store.dispatch("FETCH_ITEM", itemId);
  },
};
</script>

<style scoped>
.user-container {
  display: flex;
  align-items: center;
  padding: 0.5rem;
}
.fa-user {
  font-size: 2.5rem;
}
.user-description {
  padding-left: 8px;
}
.time {
  font-size: 0.7rem;
}
</style>

※ Font Awesome 사용하기 위해선 public/index.html에 Font Awesome CDN 추가 필요

 

결과

라우터 트랜지션(Router Transition)

라우터에서도 트랜지션을 사용 가능. 트랜지션에 대한 정보는 이전 [Vue.js] Todo App 사용자 경험 개선하기 포스팅 참조

 

구현

<transition>
  <router-view></router-view>
</transition>
728x90
반응형

댓글