[Vue3실강] 2강 어플리케이션 & 컴포넌트 인스턴스

youngseo·2022년 6월 6일
0
post-thumbnail

2강 0517

어플리케이션 & 컴포넌트 인스턴스, 라이프사이클, 클래스바인딩, 조건부렌더링, 상태유지
배열변경감지(무시), 이벤트 핸들링, 이벤트 수식어, 키수식어

1. 어플리케이션 & 컴포넌트 인스턴스

vue공식문서-어플리케이션과 컴포넌트인스턴스

Vue.createApp(App).mount('#app')

최상위 컴포넌트 App은 생명주기(라이프사이클)을 가집니다.

라이프사이클 훅

각 컴포넌트는 생성될 때 일련의 초기화 단계를 거칩니다. 예를들어 데이터 관찰, 템플릿 컴파일, 인스턴스를 DOM에 마운트, 데이터 변경 시 DOM을 업데이트해야합니다. 그 과정에서 라이프사이클 훅이라 불리우는 함수도 실행하여, 사용자가 특정 단계에서 자신의 코드를 추가할 수 있는 기회를 제공합니다.

created: 컴포넌트가 생성되고 연결이 되기 전
moutend: 컴포넌트가 연결된 직후

Intersection Observer- 요소의 가시성 관찰

<template>
  <input
    v-model="title"
    @keydown.enter="searchMovies(true)" />
  <button @click="searchMovies(true)">
    Search!
  </button>
  <ul>
    <li
      v-for="movie in customMovies"
      :key="movie.id">
      <img
        :src="movie.poster"
        alt=""
        height="40" />

      {{ movie.title }}
    </li>
  </ul>
  <div>Loading...</div>
</template>
<script>
export default {
  data() {
    return {
      title:'',
      page:1,
      movies:[],
      msg: 'HEROPY?!'
    }
  },
  methods: {
    async searchMovies(isFirst) {
      console.log(isFirst)
      if(isFirst) {
        //밑에서 push로 밀어넣기 위해서 빈배열로 초기화
        this.movies = []
        this.page=1
      }
      let res=await fetch(`https://www.omdbapi.com?apikey=7035c60c&s=${this.title}&page=${this.page}`)
      res = await res.json()
      const { Search, totalResults } = res
      this.movies.push(...Search)
      this.page += 1
    },
  }
}

</script>

vue.js의 경우 작성된 html의 코드를 가져와 내부에서 다시 코드를 만듭니다. 따라서 어디에 어떤 요소가 있는지 알고 있기 때문에 document.querySelector을 사용할 일이 거의 없습니다.

대신 ref속성을 사용합니다. 사용한 ref속성은 this.$refs.[설정한 ref속성이름]으로 사용을 할 수 있습니다.

  <div ref="observer">
    Loading...
  </div>
  created() {
    const io = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if(entry.isIntersecting) {
          console.log('교차되었음')
        }
      })
    })
    io.observe(this.$refs.observer)
  },

그런데 위와 같이 에러가 발생합니다. created는 요소에 연결되기 전이기 떄문에 발생하는 문제로 created대신 mounted에 연결해줘야합니다.

mounted() {
  const io = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      if(entry.isIntersecting) {
        console.log('교차되었음')
      }
    })
  })
  io.observe(this.$refs.observer)
},

이렇게 cretaed를 먼저 고려한 후 created가 안되는 경우 mounted를 고려해보면 됩니다.

Intersection Observer와 v-show

  <div
    v-if="hasTheRest"
    ref="observer">
    Loading...
  </div>
  data() {
    return {
      total:0,}
  },
  computed: {
    hasTheRest() {
      return this.total > this.movies.length✅
    }
  },
  methods: {
    async searchMovies(isFirst) {
      console.log(isFirst)
      if(isFirst) {
        //밑에서 push로 밀어넣기 위해서 빈배열로 초기화
        this.movies = []
        this.page=1
      }
      let res=await fetch(`https://www.omdbapi.com?apikey=7035c60c&s=${this.title}&page=${this.page}`)
      res = await res.json()
      const { Search, totalResults } = res
      this.movies.push(...Search)
      this.page += 1
      //totalResults의 경우 문자이기 때문에 숫자로 변환해줘야합니다.
      this.total=Number(totalResults)},
  }

최초 영화검색이 시작되기 전의 경우 v-if="hasTheRest"로 인해 화면에 요소의 렌더링 자체가 진행되지 않기 떄문에 다음과 같은 에러가 발생합니다.

이 때 사용을 할 수 있는 것이 바로 v-show입니다.

그런데 화면이 더 커 화면과 요소가 교차하지 않는 경우에는 버그가 생기게 됩니다.

이 문제를 해결하기 위해 searchMovies가 한번 동작을 하면 일시적으로 깜박이게 만들어줍니다.

  <div
    v-show="hasTheRest && showObserver"
    ref="observer">
    Loading...
  </div>
  data() {
    return {
      showObserver: true
    }
  methods: {
    async searchMovies(isFirst) {
      console.log(isFirst)
      if(isFirst) {
        //밑에서 push로 밀어넣기 위해서 빈배열로 초기화
        this.movies = []
        this.page=1
      }
      let res=await fetch(`https://www.omdbapi.com?apikey=7035c60c&s=${this.title}&page=${this.page}`)
      res = await res.json()
      const { Search, totalResults } = res
      this.movies.push(...Search)
      this.page += 1
      //totalResults의 경우 문자이기 때문에 숫자로 변환해줘야합니다.
      this.total=Number(totalResults)
      this.sbowObserver=falsethis.sbowObserver=true},
  }    

그런데 위와같이 작성을 하는 경우 작동을 하지 않습니다.

기본적으로 vue.js가 searchMovies라는 함수를 평가한 후에 그거에 맞게 화면에 반영을 하기 때문입니다. 이문제를 해결하기 위해 setTimeOut을 사용할 수 있습니다.

this.sbowObserver=false
setTimeout(() => {
  this.sbowObserver=true
})

Intersection Observer와 nextTick

vue.js에서 제공하는 nextTick을 이용해 setTimeout과 비슷하게 작동을 시킬 수 있습니다.

nextTick은 화면이 갱신되고 난 후에 로직을 수행할 수 있도록 합니다.

this.sbowObserver=false
this.$nextTick(() => {
  this.sbowObserver=true
})

2. 클래스와 스타일바인딩

vue.js공식문서-클래스와 스타일 바인딩

  <button
    :class="{active: movies.length}"
    @click="searchMovies(true)">
    Search!
  </button>

movies라는 배열 데이터가 있는 경우 active라는 클래스를 붙이겠다.

0개의 댓글