사이드 프로젝트 - forYourRecipe (No1. Recipe) - vue 3
현재 내가 작성하는 Vue 3 코드를 보며 의문점이 들었다.
새롭게 변화된 부분을 알고 싶어서 Vue 3를 사용해보는데 작성된 코드를 보면 Vue 2랑 완전히 똑같다...
Vue 3 Doc를 보면 setup 에 관련해서 계속 나오는데 나는 이를 전혀 사용하지 않았다.
다른 점이라고는 Vue 2 에서 @Components({}) 로 컴포넌트를 불러왔다면 @Options({}) 로 불러와야한다는 점,
store 를 사용하기 위해서 useStore() 훅을 사용한 점 말고는 완전히 똑같은 코드가 되었다.
store를 사용한 시점부터 콘솔을 열어보면 아래 이미지의 경고문이 계속 나온다.
기존 사용 방식인 class 형태의 컴포넌트에서 this.store로 접근했던 방식이 아닌 store = useStore() 로 store 객체를 만들어서 사용했는데 이 부분에서 경고 메세지가 나오는 것 같다.
Header 컴포넌트 전체 코드
<script lang="ts">
import {Options, Vue} from "vue-class-component";
import SideMenu from "@/components/common/SideMenu.vue";
import SearchInput from "@/components/common/SearchInput.vue";
import NavigationMenu from "@/components/common/NavigationMenu.vue";
import {useStore} from "vuex";
import {NAVIGATION} from "@/constant/navigation.href";
import {authService} from "@/lib/fbase";
import {signInWithPopup, GoogleAuthProvider} from "firebase/auth";
import {computed, ComputedRef} from "vue";
@Options({
components: {
SideMenu,
NavigationMenu,
SearchInput
}
})
export default class Header extends Vue {
isOpen = false;
store = useStore();
user: any = {}
isLogin: ComputedRef<boolean> = computed(() => this.store.getters["utilModule/isLogin"]);
userName: ComputedRef<string> = computed(() => this.store.getters["userModule/getName"]);
mounted() {
this.browserResizeCheck();
}
private redirectHome(): void {
this.store.commit("utilModule/setCurrentPath", 0);
this.$router.push(NAVIGATION.HOME);
}
private browserResizeCheck() {
const header = document.querySelector('.header');
window.addEventListener('resize', () => {
const width = header?.getBoundingClientRect().width;
if (width && width >= 767 && this.isOpen) this.isOpen = !this.isOpen;
})
}
private async login() {
try {
const provider = new GoogleAuthProvider()
await signInWithPopup(authService, provider)
this.user = authService.currentUser
if (this.user) {
await this.store.dispatch('userModule/login', this.user);
this.store.commit("utilModule/setIsLogin", true);
}
} catch (e) {
console.log(e);
}
}
private logout() {
authService.signOut()
this.store.commit("userModule/resetUserData");
this.store.commit('utilModule/setIsLogin', false);
}
private closeMenu(payload: boolean): void {
this.isOpen = payload;
}
private showSideMenu(): void {
this.isOpen = !this.isOpen;
}
}
</script>
문서에 따라 setup() 에서 사용해보려고 기존 코드를 아래와 같이 수정해 보았다.
<script setup>를 사용하지 않으려면 defineComponent로 묶어줘야한다.
또한 setup() {} 안에서 return {} 을 통하여 함수, data 등을 내보내주어야 사용할 수 있다.
여기서 reactive라는게 처음 쓰였는데 setup 함수 내에서 vue 2에서의 v-model 변수처럼 사용하기 위해서는 ref 나 reactive 로 묶어 줘야 유동적으로 값이 변하게 된다.
그렇지 않으면 값이 변하지 않게 된다.
2. <script setup> 없이 사용
<script lang="ts">
import {useStore} from "vuex";
import {NAVIGATION} from "@/constant/navigation.href";
import {authService} from "@/lib/fbase";
import {signInWithPopup, GoogleAuthProvider} from "firebase/auth";
import {computed, ComputedRef, defineComponent, reactive} from "vue";
import {useRouter} from "vue-router";
import NavigationMenu from "@/components/common/NavigationMenu.vue";
import SearchInput from "@/components/common/SearchInput.vue";
import SideMenu from "@/components/common/SideMenu.vue";
interface HeaderState {
isOpen: boolean,
user: any,
isLogin: ComputedRef<boolean>,
userName: ComputedRef<string>
}
export default defineComponent({
mounted() {
this.browserResizeCheck();
},
components: {
NavigationMenu,
SearchInput,
SideMenu
},
setup() {
const store = useStore();
const router = useRouter();
const state = reactive({
isOpen: false,
user: null,
isLogin: computed(() => store.getters["utilModule/isLogin"]),
userName: computed(() => store.getters["userModule/getName"]),
}) as HeaderState
const redirectHome = (): void => {
store.commit("utilModule/setCurrentPath", 0);
router.push(NAVIGATION.HOME);
}
const browserResizeCheck = (): void => {
const header = document.querySelector('.header');
window.addEventListener('resize', () => {
const width = header?.getBoundingClientRect().width;
if (width && width >= 767 && state.isOpen) state.isOpen = !state.isOpen;
})
}
const login = async (): Promise<void> => {
try {
const provider = new GoogleAuthProvider();
await signInWithPopup(authService, provider);
state.user = authService.currentUser;
if (state.user) {
await store.dispatch('userModule/login', state.user);
store.commit("utilModule/setIsLogin", true);
}
} catch (e) {
console.log(e);
}
}
const logout = (): void => {
authService.signOut();
store.commit("userModule/resetUserData");
store.commit('utilModule/setIsLogin', false);
}
const closeMenu = (payload: boolean): void => {
state.isOpen = payload;
}
const showSideMenu = (): void => {
state.isOpen = !state.isOpen;
}
return {
state,
logout,
login,
showSideMenu,
closeMenu,
browserResizeCheck,
redirectHome,
}
}
})
</script>
마지막으로 setup 함수가 아닌 script 에 setup을 선언해서 사용하는 방식
<script lang="ts" setup>
import {useStore} from "vuex";
import {NAVIGATION} from "@/constant/navigation.href";
import {authService} from "@/lib/fbase";
import {signInWithPopup, GoogleAuthProvider} from "firebase/auth";
import {computed, ComputedRef, reactive} from "vue";
import {useRouter} from "vue-router";
import NavigationMenu from "@/components/common/NavigationMenu.vue";
import SearchInput from "@/components/common/SearchInput.vue";
import SideMenu from "@/components/common/SideMenu.vue";
interface HeaderState {
isOpen: boolean,
user: any,
isLogin: ComputedRef<boolean>,
userName: ComputedRef<string>
}
const store = useStore();
const router = useRouter();
const state = reactive({
isOpen: false,
user: null,
isLogin: computed(() => store.getters["utilModule/isLogin"]),
userName: computed(() => store.getters["userModule/getName"]),
}) as HeaderState
const redirectHome = (): void => {
store.commit("utilModule/setCurrentPath", 0);
router.push(NAVIGATION.HOME);
}
const browserResizeCheck = (): void => {
const header = document.querySelector('.header');
window.addEventListener('resize', () => {
const width = header?.getBoundingClientRect().width;
if (width && width >= 767 && state.isOpen) state.isOpen = !state.isOpen;
})
}
const login = async (): Promise<void> => {
try {
const provider = new GoogleAuthProvider();
await signInWithPopup(authService, provider);
state.user = authService.currentUser;
if (state.user) {
await store.dispatch('userModule/login', state.user);
store.commit("utilModule/setIsLogin", true);
}
} catch (e) {
console.log(e);
}
}
const logout = (): void => {
authService.signOut();
store.commit("userModule/resetUserData");
store.commit('utilModule/setIsLogin', false);
}
const closeMenu = (payload: boolean): void => {
state.isOpen = payload;
}
const showSideMenu = (): void => {
state.isOpen = !state.isOpen;
}
</script>
setup() {} 을 사용한게 아니기 때문에 return 이 사라졌다.
또한 custom component를 사용하기 위해서는 단순히 <script> 내부에서 import 만 해주면 된다.
전체적으로 코드 스타일이 React와 비슷해진것 같다.
'개발노트 > Note' 카테고리의 다른 글
사이드 프로젝트 - forYourRecipe (No1. Recipe) - CI / CD (0) | 2023.03.11 |
---|---|
사이드 프로젝트 - forYourRecipe (No1. Recipe) - Docker Build (0) | 2023.03.07 |
사이드 프로젝트 - forYourRecipe (No.1 Recipe) - 프로젝트 계획 (0) | 2023.03.05 |
사이드 프로젝트 - forYourRecipe - 시작 (0) | 2023.02.16 |
사이드 프로젝트 - Dotto의 개발 일지 - 두달간의 여정 마무리 (0) | 2023.02.14 |