개발노트/Note

사이드 프로젝트 - forYourRecipe (No1. Recipe) - vue 3

Dahoon06 2023. 3. 6. 15:00
728x90
반응형

현재 내가 작성하는 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와 비슷해진것 같다.

728x90
반응형