this.$router.push(동일path)일 경우 에러가 나고 새로 고침을 하자니 SPA페이지에서 낭비인 것 같기도 해서

어떤 방식을 써야하나? 고민을 하다가 찾은 방식. (기록을 위한 작성)

검색하다가 알게된 블로그에서 3가지 방식을 알려주고 있었다. 

v-if 방식, forceUpdate 방식, 그리고 key를 통한 방식.

가장 추천하는 방식으로 (vue가 원하는..?) 진행했다.

 

레이아웃 단계에서 진행.

base-header 컴포넌트에 gnb가 있으며  nuxt 컴포넌트는 페이지이다. 

// BaseLayout.vue
<template>
	<div>
    	<base-header @forceUpdate="handleForceUpdate"/>
    </div>
    <div>
    	<Nuxt :key="componentRenderKey"/>
    </div>
    <div>
    	<base-footer />
    </div>
</template>

<script>
export default {
  name: 'BaseLayout',
  data() {
    return {
      componentRenderKey: 0,
    }
  },
  methods: {
  	handleForceUpdate() {
      // 키 값이 올라가면서 :key의 값이 변하여 Nuxt가 리렌더링된다. 
      this.componentRenderKey = this.componentRenderKey + 1;
      // 이때 스크롤까지 초기화되는 것은 아니므로 top으로 올려주기
      window.scroll(0, 0);
    },
  }
}
</script>

 

// base-header.vue
<template>
	<header>
    	<ul>
        	<li v-for="nav in gnb">
            	<nuxt-link 
                  :to="nav.path" 
                  @click.native="() => handleForceUpdate(nav.path)"  
                >
                  {{nav.name}}
                </nuxt-link>
            </li>
            // ....
        </ul>
    </header>
</template>

<script>
export default {
  name: 'BaseHeader',
  methods: {
	handleForceUpdate(to) {
      if (to === this.$route.path) {
        // 상위컴포넌트(Base Layout)로 이벤트 발생 (emit)
        this.$emit('forceUpdate');
      } else {
        this.$router.push(to);
      }
    }
  }
}
</script>

 


* 출처: 3가지 방식을 안내해줌

https://michaelnthiessen.com/force-re-render/

 

 

Nuxt Universal Mode?

 

Nuxt 프로젝트를 설정하는 중에 Rendering mode에 대해 궁금증이 생겼다.

SPA나 SSR 방식은 알고있다고 생각했는데, Universal은 뭘까? 간단히 알아보기로 했다.

 

SSG (Server Side Generation or Static Side Generation)

(참고: https://velog.io/@longroadhome/FE-SSRServer-Side-Rendering-%EA%B7%B8%EB%A6%AC%EA%B3%A0-SSGStatic-Site-Generation-feat.-NEXT%EB%A5%BC-%EC%A4%91%EC%8B%AC%EC%9C%BC%EB%A1%9C)

 

 

Nuxt Universal Mode?

 

먼저 짧게 요약하자면

몇 가지 기능을 포함하여 SSR과 CSR 방식 둘 다 상황에 맞게 사용하여 단점을 개선한 모드이다.

초기 렌더링 속도를 위해 Server Side Rendering 방식을 사용하고 페이지간 이동 시에는 Client Side Rendering을 사용한다.

 

어떻게 구현할 수 있었을까?

핵심은 하이드레이션(Client Side Hydration), 코드 분할(Code Splitting), 프리패칭(Prefetching)이라고 한다.

 

 

 

1. 하이드레이션

참고 글을 보았지만 이해가가지 않아서.. 참고 글을 읽어보길 권유합니다.

초기 렌더링에서 서버로부터 정적 html과 자바스크립트 번들을 함께 가져온다.

그리고 이 번들을 통해 정적 html을 다이나믹 DOM 상태로 바꾼다.

다이나믹 DOM은 리렌더링없이 사용자와 상호작용을 할 수 있다고 한다. 

 

 

 

2. 코드분할

코드 전체를 로드하지 않고 필요한 곳에 맞춰 분할해서 가져오는 것을 말한다.

Universal 모드에서는 렌더링에 필요한 곳에 맞게 자동으로 코드를 분할하여 가져오게되어 

로딩속도가 빨라진다. 그리고 가져온 번들은 캐싱되어 재활용된다.

 

 

 

3. 프리패칭

<NuxtLink />가 페이지에 있을 경우, 해당 페이지들을 미리 서버에 요청하여 준비한다.

(뷰포트에 이동할 페이지 링크가 보이기만해도 번들에 요청)

따라서 이미 클라이언트에 준비가 되어있으므로 페이지간 이동 속도가 빠르다.

 

 


 

출처

https://joshua1988.github.io/vue-camp/nuxt/universal-mode.html

 

 

설치

npm i vuex

 

store 폴더에 관리하기 위해 store폴더, 파일 생성

store 폴더

 

store/store.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
  	//...
  },
  getter: {
  	//...
  },
  mutations: {
  	//...  
  },
  action: {
  	//...
  }
})

이런 형태로 작업하면 된다.

- state: 여러 컴포넌트에 공유되는 데이터

- getter: 연산된 state값을 접근하는 속성

- mutations: state값을 변경하는 이벤트 로직이나 메서드

- actions: 비동기 처리 로직을 선언하는 메서드

 

그리고 store 파일을 등록해줘야한다.

 

 

main.js

main.js

 

state

// vue파일 안에서 작업할 경우
// App.vue
data: {
    message: 'hello',
}
<p>{{ message }}</p>    

// store를 통해 작업할 경우
// store.js
state: {
    message: 'hello',
}

// App.vue
<p>{{ this.$store.state.message }}</p>
// App.vue
data: {
    message: 'hello',
}
<p>{{ message }}</p>    

// store.js
state: {
    message: 'hello',
}

// App.vue
<p>{{ this.$store.state.message }}</p>

 

 

getters

state에 접근하는 속성

computed()처럼 미리 연산된 값을 접근하는 속성

// store.js
getters: {
    getNumber(state){
        return state.num;
    },
    doubleNumber(state){
        return state.num * 2;
    }
}

// App.vue
<p>{{ this.$store.getters.getNumber }}</p>
<p>{{ this.$store.getters.doubleNumber }}</p>

 

 

mutations

state 값을 변경할 수 있는 유일한 방법,

mutations을 통해서 작업해야 devtools에서 추적이 가능.

devtools를 통해 유일한 추적

// store.js
mutations: {
    printNumbers(state) {
        return state.num
    },
    sumNumbers(state, anotherNum) {
        return state.num + anotherNum;
    }
},

// App.vue
this.$store.commit('printNumbers');
this.$store.commit('sumNumbers', 20);

// state를 변경하기 위해 mutations를 동작시킬 때 인자(payload)를 전달할 수 있음
// store.js
mutations: {
    modifyState(state, payload) {
        console.log(payload.str);
        return state.storeNum += payload.num;
    }
}

// App.vue
this.$store.commit('modifyState', {
    str: 'passed from payload',
    num: 20
});

 

 

actions

비동기 처리 로직을 선언하는 메서드. 비동기 로직을 담당하는 mutations

데이터 요청, promise, es6 async과 같은 비동기 처리는 모두 actions에 선언

// store.js
mutation: {
    doubleNumber(state) {
        state.num * 2;
    }
},
actions: {
    delayDoubleNumber(context) { 
                // context로 store의 메서드와 속성 접근
        context.commit('doubleNumber');
    }
}

// App.vue
// dispatch로 actions 호출
this.$store.dispatch('delayDoubleNumber');

actions에서 mutation에 접근하기 위한 경로로 첫번째 인자 context가 존재한다.

 

비동기 예제1

// store.js
mutations: {
    addCounter(state) {
        state.counter++;
    }
},
actions: {
    delayedAddCounter(context) {
        setTimeout(() => context.commit('addCounter'), 2000);
    }
}

// App.vue
methods: {
    incrementCounter(){
        this.$store.dispatch('delayedAddCounter');
    }
}

 

비동기 예제2

// store.js
mutations: {
    setData(state, fetchedData){
        state.product = fetchedData;
    }
},
actions: {
    fetchProductData(context) {
        return axios.get('https://domain.com/products/1')
.then(res => context.commit('setData', res));
    }
}

// App.vue
methods: {
    getProduct() {
        this.$store.dispatch('fetchProductData');
    }
}

 

내가 기억하기 위해 작성 ㅎㅎㅎ(머쓱)

 

 

1.파이어베이스 콘솔 사이트로 이동해서 가입한다.

https://console.firebase.google.com/

 

 

 

2.새 프로젝트 추가

- 프로젝트명이 url에 표기됨 [ 대략적 예시) 프로젝트명.firebase.com 형식 ]

 

 

 

3.내 프로젝트로 가서 firebase CLI 설치

[cmd]

npm install -g firebase-tools

firebase login

- 가입한 계정으로 로그인

 

 

 

4.내 프로젝트에서 init

[cmd]

firebase init

 

질문들이 나오는데 답변하면 된다.

대충..

 

- Are you ready to proceed?(Y/n) Y

 

-

Database, Hosting에서 스페이스 바 눌러서 체크하고 다 체크하면 엔터쳐서 다음 질문으로 간다.

더 필요하면 더 체크하세요.

 

-

Use an existing project 기존 프로젝트 사용

 

-

해당 프로젝트 명

 

-

해당 rulse 파일 사용하기 위해 그대로 엔터

 

-

vue-cli에서 build하면 dist를 public directory로 생성하므로 dist 작성

 

-

싱글 앱 여부 y

 

-

dist/index.html에 파일을 덮여쓸 것인지 n

 

 

 

5.진행이 완료되면 내 프로젝트에

.firebaserc, database.rules.json, firebase.json파일이 생성된 것을 확인할 수 있다.

 

 

 

6.내 프로젝트에서 명령어 작성

[cmd]

firebase serve

firebase deploy

 

firebase serve는 로컬에서 보기

firebase deploy는 배포하기

 

7. 배포 후 호스팅 url 정보가 나온다.

 

접속하면 끝!

 

 

 

+ Recent posts