Vue.js 3 & NodeJS/Vue 3

Vue CLI Store 데이터 유지(페이지 새로고침 - 초기화 방지) - Vue CLI Vuex Store State, Page Refresh, PersistedState

carrotweb 2022. 1. 31. 19:19
728x90
반응형

세 번째로 Vuex PersistedState를 사용하는 방법을 알아보도록 하겠습니다.

Vuex PersistedState는 Local Storage(로컬 스토리지)를 사용하여 state를 저장하고 유지합니다.

Vuex PersistedState 설치하기

콘솔을 실행하고 Vue 프로젝트가 있는 C:\workspaces\nodeserver\testvue 폴더로 이동합니다.

Vue 프로젝트에 vuex-persistedstate를 설치하기 위해 콘솔에서 npm install 명령어를 실행합니다.

npm install --save vuex-persistedstate

또는 버전 적용
npm install --save vuex-persistedstate@4.1.0

npm install에 옵션으로 --save를 추가하면 자동으로 package.json 파일의 "dependencies"에 "vuex-persistedstate" 항목이 추가됩니다.

 

 

package.json 파일의 "dependencies"입니다.

"dependencies": {
  "axios": "^0.21.1",
  "core-js": "^3.6.5",
  "vue": "^3.0.0",
  "vue-router": "^4.0.0-0",
  "vue3-cookies": "^1.0.6",
  "vuex": "^4.0.2",
  "vuex-persistedstate": "^4.1.0" --> 추가
}

 

 

테스트를 위해 cookie(쿠키)의 데이터는 삭제해 주시기 바랍니다.

그리고 C:\workspaces\nodeserver\testvue\src\store\modules\login.js 파일을 오픈합니다.

cookie가 적용된 부분을 주석 처리하거나 삭제합니다.

import axios from 'axios';
//import { useCookies } from "vue3-cookies";

const axiosRefresh = axios.create();
//const { cookies } = useCookies();

 

mutations에서 reset() 함수에 있는 cookie를 주석 처리하거나 삭제합니다.

saveStateToStorage() 함수와 readStateFromStorage() 함수를 주석 처리하거나 삭제합니다.

mutations: {
	// memberId를 설정합니다.
	setMmemberId(state, memberId) {
		state.memberId = memberId;
	},
	// Access-Token를 설정합니다.
	setAccessToken(state, accessToken) {
		state.accessToken = accessToken;
	},
	// Refresh-Token를 설정합니다.
	setRefreshToken(state, refreshToken) {
		state.refreshToken = refreshToken;
	},
	// 초기화시킵니다.
	reset(state) {
		state.memberId = '';
		state.accessToken = '';
		state.refreshToken = '';
		//cookies.remove("testvue.login.memberId");
		//cookies.remove("testvue.login.accessToke");
		//cookies.remove("testvue.login.refreshToken");
		//cookies.remove("testvue.login");
	}
	/*
	// Storage에 state를 저장합니다.
	saveStateToStorage(state) {
		//cookies.set("testvue.login.memberId", state.memberId, 60 * 60 * 24 * 30);
		//cookies.set("testvue.login.accessToke", state.accessToken, 60 * 60 * 24 * 30);
		//cookies.set("testvue.login.refreshToken", state.refreshToken, 60 * 60 * 24 * 30);
		//cookies.set("testvue.login", JSON.stringify(state), 60 * 60 * 24 * 30);
	},
	// Storage에서 state를 읽어옵니다.
	readStateFromStorage(state) {
		//if (cookies.get("testvue.login.memberId") != null) {
		//	state.memberId = cookies.get("testvue.login.memberId");
		//}
		//if (cookies.get("testvue.login.accessToken") != null) {
		//	state.accessToken = cookies.get("testvue.login.accessToken");
		//}
		//if (cookies.get("testvue.login.refreshToken") != null) {
		//	state.refreshToken = cookies.get("testvue.login.refreshToken");
		//}
		//if (cookies.get("testvue.login") != null) {
		//	let storage = cookies.get("testvue.login");
		//	if (storage.memberId != null) {
		//		state.memberId = storage.memberId;
		//	}
		//	if (storage.accessToken != null) {
		//		state.accessToken = storage.accessToken;
		//	}
		//	if (storage.memberId != null) {
		//		state.refreshToken = storage.refreshToken;
		//	}
		//}
	}
	*/
}

 

actions에서 doLogin() 함수에서 commit('saveStateToStorage') 메서드를 주석 처리하거나 삭제합니다. 그리고 doReadStateFromStorage() 함수를 주석 처리 또는 삭제합니다.

actions: {
	// 로그인합니다.
	async doLogin({ commit }, memberInfo) {
		let result = false;
		let resultErr = null;
		try {
			let res = await axios.post("http://localhost:9000/members/login", memberInfo);
			if (res.data.success == true) {
				console.log("로그인되었습니다.");
				commit('setMmemberId', memberInfo.id);
				commit('setAccessToken', res.data.accessToken);
				commit('setRefreshToken', res.data.refreshToken);
				// Storage에 state를 저장합니다.
				//commit('saveStateToStorage');
				axios.defaults.headers.common['Access-Token'] = res.data.accessToken;
				result = true;
			} else {
				console.log("로그인되지 않았습니다.");
				let err = new Error("Request failed with status code 401");
				err.status = 401;
				err.response = {data:{"success":false, "errormessage":"로그인되지 않았습니다."}};
				resultErr = err;
			}
		} catch(err) {
			if (!err.response) {
				err.response = {data:{"success":false, "errormessage":err.message}};
			}
			resultErr = err;
		}
		return new Promise((resolve, reject) => {
			if (result) {
				resolve();
			} else {
				reject(resultErr);
			}
		});
	},
	// 로그아웃합니다.
	doLogout({commit}) {
		commit('reset');
		delete axios.defaults.headers.common['Access-Token'];
	},
	// Access-Token를 갱신합니다.
	async doRefreshToken({commit, state}) {
		let result = false;
		let resultErr = null;
		if (state.accessToken != "") {
			let token = { id: state.memberId, accessToken : state.accessToken, refreshToken : state.refreshToken };
			try {
				let res = await axiosRefresh.post("http://localhost:9000/members/refresh", token);
				if (res.data.success == true) {
					console.log("Access-Token이 갱신되었습니다.");
					commit('setAccessToken', res.data.accessToken);
					console.log(res.data.accessToken);
					axios.defaults.headers.common['Access-Token'] = res.data.accessToken;
					result = true;
				} else {
					console.log("Access-Token이 갱신되지 않았습니다.");
					let err = new Error("Request failed with status code 401");
					err.status = 401;
					err.response = {data:{"success":false, "errormessage":"Access-Token이 갱신되었습니다."}};
					resultErr = err;
				}
			} catch(err) {
				//console.log(err);
				if (!err.response) {
					err.response = {data:{"success":false, "errormessage":err.message}};
				}
				resultErr = err;
			}
		} else {
			let err = new Error("Access-Token does not exist");
			err.status = 401;
			err.response = {data:{"success":false, "errormessage":"Access-Token이 없습니다."}};
			resultErr = err;
		}
		return new Promise((resolve, reject) => {
			if (result) {
				resolve();
			} else {
				reject(resultErr);
			}
		});
	}
	/*
	doReadStateFromStorage({commit}) {
		commit('readStateFromStorage');
	}
	*/
}

 

그리고 C:\workspaces\nodeserver\testvue\src\App.vue 파일을 오픈하여 <script>에서 mounted() 함수를 주석 처리하거나 삭제합니다.

<script>
export default {
	name : 'App',
	methods : {
		Logout() {
			this.$store.dispatch("loginStore/doLogout");
			this.$router.push('/');
		}
	},
	computed : {
		isLogin() {
			return this.$store.getters['loginStore/isLogin'];
		}
	}
	/*
	mounted() {
		this.$store.dispatch("loginStore/doReadStateFromStorage");
	}
	*/
};
</script>

 

반응형

 

 

Vuex PersistedState로 state 저장하고 읽기

1. C:\workspaces\nodeserver\testvue\src\store\index.js 파일을 오픈합니다.

vuex-persistedstate를 import 합니다.

import createPersistedState from "vuex-persistedstate";

 

createPersistedState를 사용하여 로그인 모듈(loginStore)을 추가합니다.

const storageState = createPersistedState({
  paths: ['loginStore']
});

여러 개의 모듈을 paths에 콤마(,) 추가할 수 있습니다.

createStore() 메서드에 plugin으로 추가합니다.

export default createStore({
	modules: {
		scoreStore: scoreStore,
		loginStore: loginStore
	},
	plugins: [storageState]
});

만약, 개별 모듈이 아닌 전체 모듈을 저장하고 싶을 경우에는 모듈 추가 없이 바로 적용하면 됩니다.

export default createStore({
	modules: {
		scoreStore: scoreStore,
		loginStore: loginStore
	},
	plugins: [createPersistedState()]
});

 

 

전체 소스입니다.

import { createStore } from 'vuex';
import createPersistedState from "vuex-persistedstate";
import scoreStore from '@/store/modules/score.js';
import loginStore from '@/store/modules/login.js';

const storageState = createPersistedState({
  paths: ['loginStore']
});

export default createStore({
	modules: {
		scoreStore: scoreStore,
		loginStore: loginStore
	},
	plugins: [storageState]
});

 

2. 콘솔을 실행하고 Node.js 레스트 API 서버 프로젝트가 있는 C:\workspaces\nodeserver\testrestapi 폴더로 이동합니다. 그리고 npm run 명령어를 실행합니다.

npm run start

 

3. 콘솔을 실행하고 Vue 프로젝트가 있는 C:\workspaces\nodeserver\testvue 폴더로 이동합니다. 그리고 콘솔에서 npm run 명령어를 실행합니다.

npm run serve

 

4. 로그인을 합니다. 그러면 Application의 Local Storage(로컬 스토리지)에 vuex로 로그인 모듈(loginStore)의 state가 JSON 객체로 저장되어 있는 것을 확인할 수 있습니다.

그리고 웹 브라우저에서 새로고침(F5)을 하여도 로그인이 유지되는 것을 확인할 수 있습니다.

 

5. 로그아웃을 클릭합니다. 그러면 Application의 Local Storage(로컬 스토리지)에 vuex가 내용이 없는 빈 JSON 객체로 저장되는 것을 확인할 수 있습니다.

 

Vuex PersistedState를 사용하면 쉽게 state를 저장하고 유지할 수 있습니다.

프로젝트에 따라 개발 환경에 따라 Local Storage(로컬 스토리지)나 cookie(쿠키)로 사용해야 부분이 있습니다.

그리고 Vuex PersistedState는 모듈 자체를 저장하기 때문에 저장이 필요하지 않은 state도 저장되어 모듈 설계에 따라 비효율적일 수 있습니다. 그래서 모듈을 설계할 때 고려하시거나 개별 저장이 효율적이라고 판단될 때는 Local Storage(로컬 스토리지)를 사용하시길 바랍니다.

cookie(쿠키)는 만료 기간이 정해져 있고 웹 브라우저마다 cookie(쿠키)가 차단될 수 있습니다. 그래서 cookie(쿠키)를 사용하실 때는 사용자에게 cookie(쿠키) 사용을 확인받아 설정해야 하는 부분을 고려해야 합니다.

728x90
반응형