프론트/Vue

[Nuxt] 로그인 적용, 글 작성

ZestLee 2022. 2. 6. 20:07

2019-11 에 쓴 글입니다.

이전 포스트에서는 회원가입과 로그인 설정까지 해 보았습니다. 이번 포스팅에서는 전 포스트에서 말씀드린 getMemberInfo 함수를 따로 뺀 이유와, login 적용에 대하여 작성하도록 하겠습니다.

1. 로그인 적용

로그인 페이지의 template과, vuex의 로그인 함수들을 전부 만들었다면, 이제 로그인 적용을 시켜야 할 텐데요. 저는 mapState와, mapActions를 통하여 Vuex의 로그인 함수를 연결시키도록 하겠습니다.

 

여기에서 mapState와 mapActions가 생소한 분들을 위하여 간단하게 설명해 드리겠습니다.

 

제가 사용한 Vuex 중앙 통제 저장 관리소에서는 컴포넌트에서 Vuex의 데이터들에 접근할 때 중복된 코드를 반복 호출해야 된다는 문제점이 있습니다. 그리고 역시나 이를 해결하기 위하여 vue에는 helper들이 있습니다.

vuex의 state와 연결 시켜 주기 위해서 mapState를 이용하고, vuex의 actions와 연결 시켜 주기 위해서 mapActions를 이용합니다.

이제 코드를 보며 살펴 보겠습니다.

import { mapState, mapActions } from "vuex";
export default {
 data() {
  return {
   password: null,
   username: null
  };
 },
 computed: {
  ...mapState(["user"])
 },
 methods: {
  ...mapActions({ 
   login: "user/login"
  })
 }
};

먼저 mapState와 mapActions를 import 시켜 줍니다. mapState, mapActions 내용들은 vuex 에 들어있기 때문에, store/user.js가 아닌 vuex 에서 import를 시켜 줍니다.

 

vuex의 user state를 computed로 불러 오고, login 함수를 methods로 불러 옵니다. (matState, mapGetters -> computed, mapActions, mapMutations -> methods인데, 이는 필수 사항이 아닌 권장 사항입니다.)

 

그리고, mapState 앞에 붙은 … 점 세 개는 스프레드 문법입니다.

더보기
더보기

스프레드 문법이 궁금하다면...  이 글을 확인해 주세요.

자, 이렇게 스크립트를 모두 작성했으면, 템플릿에 적용시키겠습니다. 로그인 함수를 호출할 부분에 @click=”login({ username, password})” 이처럼 클릭 이벤트를 넣어 주세요.

 

로그인이 잘 실행되는 것을 볼 수 있으실 겁니다. 다른 페이지로 이동하더라도 로그인 상태는 지속되는 모습을 볼 수 있습니다.

 

자, 이제 새로고침을 한번 해 볼까요?

 

새로고침을 하면 현재 로그인 상태가 풀리는 것을 볼 수 있으실 겁니다. 이는 vue의 state가 새로고침 되면서 발생하는 현상인데요, 이를 해결하기 위해서 로그인할 때 localStorage에 모든 정보를 저장하는 방법도 있지만, 이는 데이터를 보호하는 데에 있어서 위험한 방법이기 때문에, 저는 토큰만을 세션에 저장하는 형태로 만들었습니다.

 

이를 해결하기 위해서 저는 저번 포스팅에서 보여 드린 store > user.js > getMemberInfo 를 따로 적은 것입니다.

 

getMemberInfo 함수는, 세션에 저장한 토큰을 가지고 유저 정보들을 가지고 오는 형태인데요, 이 함수를 어딘가에 두면 새로고침을 하더라도 이 함수를 실행시켜 state를 유지할 수 있을 겁니다. 자, 어디에 두면 될까요?

 

맞습니다. default.vue 가 렌더링 진행되기 전 부분에 두면 페이지 자체가 만들어질 때 실행되기 때문에 state를 유지할 수 있을 겁니다. 그래서 저는 default.vue에 다음과 같이 코드를 추가하겠습니다.

import store from "../store/user";

export default {
 ...
 beforeCreate() {
  this.$store.dispatch("user/getMemberInfo");
 }
}

default.vue 가 렌더링 되기 전에 실행하기 위하여 beforeCreate 를 사용했고, store의 actions를 dispatch로 실행하였습니다.

그리고 나서 다시 새로고침을 해 보시면, 로그인 상태가 유지되는 것을 보실 수 있을 겁니다.

2. 글 작성

유저를 생성하였으니, 이제 글 작성을 해야 되겠죠? pages에 글 작성을 위한 vue 파일 한 개를 추가해 주고, 그 안에 글 작성을 위한 컴포넌트를 추가해 주겠습니다.

저는 글 작성 컴포넌트를 Vuetify의 dialog를 이용하여 만들겠습니다.

글 작성 버튼을 누를 경우 dialog가 오픈 되고, 그 안에 들어있는 text field를 채워 글 작성 함수를 호출할 경우, 그 안의 내용들을 form으로 서버에 보내는 형태로 만들 것입니다.

스크립트에 다음을 추가해 주겠습니다.

<script>
export default {
  data() {
    return {
      ...
    };
  },
  methods: {
    getToday() {
      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth() + 1;
      var yyyy = today.getFullYear();
      if (dd < 10) {
        dd = "0" + dd;
      }
      if (mm < 10) {
        mm = "0" + mm;
      }
      today = yyyy + "/" + dd + "/" + mm;
      return today;
    },
    
    async submitPost() {
      this.post.date = this.getToday()
      
      if(this.infoPhoto != null){
        this.post.infoPhoto = this.infoPhoto
      }
      
      if(this.infoFile != null){
        this.post.infoFile = this.infoFile
      }
      
      let token = ""
      
      if(process.browser){
        this.post.userId = sessionStorage.getItem("user_idx")
        token = sessionStorage.getItem("access-token")
      }
      
      const config = {
        headers: { "Content-Type": "multipart/form-data", "Authorization" : "Token "+token}
      }
      
      const formData = new FormData()
      
      for (let data in this.post) {
        formData.append(data, this.post[data])
      }
      
      try {
        let response = await this.$axios.$post("/posts/", formData, config)
        this.$router.push("/")
        this.dialog = false
      } catch (e) {
        console.log(e.response)
      }
    }
  }
};
</script>

form을 보내기 위해 post를 먼저 초기화해 주고, methods를 만들어 줍니다.

 

getToday는 오늘 날짜를 자바스크립트로 받아 오고, 형태를 바꿔 주는 함수입니다.

 

그 다음으로 submitPost는, dialog에서 입력한 내용들을 post에 넣어 주고, 데이터들을 form data 에 넣어 서버에 보내 주는 함수입니다. 이는 회원가입할 때 설명했으므로 생략하겠습니다.

여기에서 process.browser는 클라이언트에서만 실행할 때 쓰는 조건인데, token을 받아 올 때 세션에 접근하는데, 서버 측 렌더링에서 이를 실행할 수 없으므로 추가해 줬습니다. (이를 추가하지 않을 경우, document undefined 에러가 납니다.)

infoFile과 post의 infoFile을 다르게 둔 이유는, post 객체 안에 infoFile을 null 로 선언할 경우, 객체에 null 값이 들어갈 수 없기 때문에 에러가 나기 때문입니다. 따라서 따로 선언한 후, 함수 안에서 값을 넣어 줬습니다.

그리고 작성 버튼을 눌러 확인하면, 글 작성까지 완료됐습니다!

이제 글을 표출하고 서버 렌더링을 확인만 하면 최종 목표가 완성됩니다. 이 내용은 다음 포스트에 이어 작성하겠습니다.