인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

김지수님의 프로필 이미지
김지수

작성한 질문수

프로젝트로 배우는 Vue.js 3

[55강 메모리 누수 관리] toast timer clear 오류

작성

·

283

0

코지코더님 안녕하세요.
양질에 강의에 감사드리며, 55강을 듣다가 2가지 의문점이 생겨 문의 드립니다.

질문1) toastTimer가 삭제되지 않는 현상

onUnmounted hook에서 toastTimer를 삭제하는 로직의 동작이 강의 내용과 상이하여 문의 드립니다.

강의와 동일하게 소스를 작성하였는데, 콘솔을 보면

onUnmounted
timeout

이 출력됩니다. timeout이 출력되지 않아야 맞는 동작인 것 같은데 왜 clear 되지 않는 걸까요?

_id.vue 전체 소스는 하단에 첨부하였습니다!

    const toastTimer = ref(null);
    const triggerToast = (message, type = 'success') => {
      toastMessage.value = message;
      toastType.value = type;
      showToast.value = true;
      toastTimer.value = setTimeout(() => {
        console.log('timeout');
        toastMessage.value = '';
        toastType.value = '';
        showToast.value = false;
      }, 3000);
    };

    onUnmounted(() => {
      console.log('onUnmounted');
      clearTimeout(toastTimer.value);
    });

 

질문2) timer 변수에 ref를 사용하지 않아도 되는가?

강의에서 const toastTimer = ref(null); 과 같이 timer를 담는 변수에도 ref로 감싸셨는데요,
ref로 감싸지 않고 let 으로 선언하면 안 되나요?

 

----

<template>
  <h2>To-Do Page</h2>
  <div v-if="loading">Loading...</div>
  <form
    v-else
    @submit.prevent="onSave">
    <div class="row">
      <div class="col-6">
        <div class="form-group mb-2">
          <label class="my-2">Todo Subject</label>
          <input type="text" class="form-control" v-model="todo.title">
        </div>
        <button type="button" class="btn btn-outline-dark">Cancel</button>
        <button
          type="submit"
          class="btn btn-primary ms-2"
          :disabled="!todoUpdated"
          @click.stop="onSave"
        >Save</button>
      </div>
      <div class="col-6">
        <div class="form-group">
          <label class="my-2">Status</label>
        </div>
        <button
          type="button"
          class="btn btn-primary"
          :class="statusBtnClass"
          @click="toggleTodoStatus"
        >{{ statusBtnLabel }}</button>
      </div>
    </div>
  </form>
  <Toast v-if="showToast" :message="toastMessage" :type="toastType"></Toast>
</template>

<script>
import { useRoute } from 'vue-router';
import { ref, computed, onUnmounted } from 'vue';
import _ from 'lodash';

import { getTodoItem, putTodoItem } from '@/api';
import Toast from '@/components/Toast.vue';

export default {
  setup() {
    const route = useRoute();
    const todoId = route.params.id;

    const todo = ref(null);
    const originTodo = ref(null);

    const loading = ref(true);

    const showToast = ref(false);
    const toastType = ref('success');
    const toastMessage = ref('');
    const toastTimer = ref(null);
    const triggerToast = (message, type = 'success') => {
      toastMessage.value = message;
      toastType.value = type;
      showToast.value = true;
      toastTimer.value = setTimeout(() => {
        console.log('timeout');
        toastMessage.value = '';
        toastType.value = '';
        showToast.value = false;
      }, 3000);
    };

    onUnmounted(() => {
      console.log('onUnmounted');
      clearTimeout(toastTimer.value);
    });

    const getTodo = async () => {
      try {
        const res = await getTodoItem(todoId);
        todo.value = res.data;
        originTodo.value = { ...res.data };
        loading.value = false;
      } catch (err) {
        triggerToast('Error occurred!', 'danger');
      }
    };

    const statusBtnClass = computed(() => (todo.value.done ? 'btn-success' : 'btn-danger'));
    const statusBtnLabel = computed(() => (todo.value.done ? 'Completed' : 'Incompleted'));

    const toggleTodoStatus = () => {
      todo.value.done = !todo.value.done;
    };

    const todoUpdated = computed(() => !_.isEqual(todo.value, originTodo.value));

    const onSave = async () => {
      try {
        const { data } = await putTodoItem(todoId, todo.value);
        originTodo.value = { ...data };
        triggerToast('Successfully saved!');
      } catch (err) {
        triggerToast('Error occurred!', 'danger');
      }
    };

    getTodo();

    return {
      todo,
      loading,
      statusBtnClass,
      statusBtnLabel,
      toggleTodoStatus,
      todoUpdated,
      onSave,
      showToast,
      toastMessage,
      toastType,
    };
  },
  components: {
    Toast,
  },
};
</script>

<style scoped>

</style>

 

답변 2

1

코지 코더님의 프로필 이미지
코지 코더
지식공유자

질문 1. form 태그에 @submit에서 onSave 함수를 사용하고 있고 button에도 @click에서 onSave를 실행해하고 있습니다. 그래서 setTimeout이 두번 실행되고 clear 할때 하나는 clear 되지 않아서 그런거 같아요.

onSave를 한번만 실행할수 있게 둘중에 하나를 지우시면 잘 작동할거 같네요

 

질문 2. let 사용하셔도 됩니다

 

확인해보시고 안되면 또 댓글 남겨주세요 ^^

0

김지수님의 프로필 이미지
김지수
질문자

코지 코더님, form 태그의 onSave를 삭제하였더니 강의와 동일하게 동작합니다!

빠르고 친절한 답변에 감사드립니다.

 

 

김지수님의 프로필 이미지
김지수

작성한 질문수

질문하기