【vue3】워치 리스너 사용법

계산된 속성을 사용하면 파생된 값을 선언적으로 계산할 수 있습니다. 그러나 어떤 경우에는 상태가 변경될 때 DOM을 변경하거나 비동기 작업의 결과에 따라 다른 위치의 상태를 수정하는 등의 "부작용"을 수행해야 합니다.

복합 API에서는 watch 함수를 사용하여 반응 상태가 변경될 때마다 콜백 함수를 트리거 할 수 있습니다 .

<script setup>
import {
      
       ref, watch } from 'vue'

const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')

// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
      
      
  if (newQuestion.indexOf('?') > -1) {
      
      
    answer.value = 'Thinking...'
    try {
      
      
      const res = await fetch('https://yesno.wtf/api')
      answer.value = (await res.json()).answer
    } catch (error) {
      
      
      answer.value = 'Error! Could not reach the API. ' + error
    }
  }
})
</script>

<template>
  <p>
    Ask a yes/no question:
    <input v-model="question" />
  </p>
  <p>{
   
   { answer }}</p>
</template>

훈련장에서 사용해 보세요.

청취 데이터 소스 유형

watch의 첫 번째 매개변수는 다양한 형식의 "데이터 소스"일 수 있습니다. 즉, 참조(계산된 속성 포함), 반응형 개체, getter 함수 또는 여러 데이터 소스의 배열일 수 있습니다.

const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
    
    
  console.log(`x is ${
      
      newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    
    
    console.log(`sum of x + y is: ${
      
      sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
    
    
  console.log(`x is ${
      
      newX} and y is ${
      
      newY}`)
})

반응형 객체의 속성 값을 직접 들을 수는 없습니다. 예를 들면 다음과 같습니다.

const obj = reactive({
    
     count: 0 })

// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
    
    
  console.log(`count is: ${
      
      count}`)
})

여기서는 속성을 반환하는 getter 함수를 사용해야 합니다.

// 提供一个 getter 函数
watch(
  () => obj.count,
  (count) => {
    
    
    console.log(`count is: ${
      
      count}`)
  }
)

깊은 청취자

반응형 객체를 watch()에 직접 전달하면 암시적으로 딥 리스너가 생성됩니다. 이 콜백 함수는 모든 중첩된 변경 사항에 대해 트리거됩니다.

const obj = reactive({
    
     count: 0 })

watch(obj, (newValue, oldValue) => {
    
    
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
})

obj.count++

대조적으로, 반응형 객체를 반환하는 getter 함수는 다른 객체를 반환하는 경우에만 콜백을 트리거합니다.

watch(
  () => state.someObject,
  () => {
    
    
    // 仅当 state.someObject 被替换时触发
  }
)

위 예제에 deep 옵션을 명시적으로 추가하여 딥 리스너가 되도록 할 수도 있습니다.

watch(
  () => state.someObject,
  (newValue, oldValue) => {
    
    
    // 注意:`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
  },
  {
    
     deep: true }
)

주의해서 사용하세요

심층 청취를 위해서는 청취 중인 객체의 모든 중첩 속성을 탐색해야 하는데, 이는 대규모 데이터 구조에 사용될 때 비용이 매우 많이 듭니다. 따라서 필요할 때만 사용하고 성능에 주의를 기울이십시오.

즉각적인 콜백을 위한 리스너

Watch는 기본적으로 지연됩니다. 콜백은 데이터 소스가 변경될 때만 실행됩니다. 그러나 일부 시나리오에서는 리스너를 생성할 때 즉시 콜백을 실행하려고 합니다. 예를 들어 초기 데이터를 요청한 다음 해당 상태가 변경되면 데이터를 다시 요청하고 싶습니다.

immediate: true옵션을 전달하여 리스너의 콜백이 즉시 실행되도록 할 수 있습니다 .

watch(source, (newValue, oldValue) => {
    
    
  // 立即执行,且当 `source` 改变时再次执行
}, {
    
     immediate: true })

시계효과()

리스너의 콜백이 소스와 정확히 동일한 반응 상태를 사용하는 것이 일반적입니다. 예를 들어, 다음 코드는 todoId에 대한 참조가 변경될 때마다 리스너를 사용하여 원격 리소스를 로드합니다.

const todoId = ref(1)
const data = ref(null)

watch(todoId, async () => {
    
    
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${
      
      todoId.value}`
  )
  data.value = await response.json()
}, {
    
     immediate: true })

특히 리스너가 todoId소스로 한 번, 콜백에서 한 번, 두 번 사용되는 방식에 주목하세요.

watchEffect 함수를 사용하여 위 코드를 단순화할 수 있습니다. watchEffect()를 사용하면 콜백의 반응적 종속성을 자동으로 추적할 수 있습니다. 위의 리스너는 다음과 같이 다시 작성할 수 있습니다.

watchEffect(async () => {
    
    
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${
      
      todoId.value}`
  )
  data.value = await response.json()
})

이 예시에서는 콜백이 즉시 실행되며, instant: true를 지정할 필요가 없습니다. 실행 중에 todoId.value를 종속성으로 자동 추적합니다 (계산된 속성과 유사). todoId.value가 변경될 때마다 콜백이 다시 실행됩니다. watchEffect()를 사용하면 더 이상 todoId를 소스 값으로 명시적으로 전달할 필요가 없습니다.

종속성이 하나만 있는 이와 같은 예의 경우 watchEffect()의 이점은 상대적으로 작습니다. 그러나 여러 종속성이 있는 리스너의 경우 watchEffect()를 사용하면 종속성 목록을 수동으로 유지 관리해야 하는 부담이 사라집니다. 또한 중첩된 데이터 구조에서 여러 속성을 수신해야 하는 경우 watchEffect()는 모든 속성을 재귀적으로 추적하는 대신 콜백에 사용되는 속성만 추적하므로 딥 리스너보다 더 효율적일 수 있습니다.


watchEffect는 동기 실행 중에만 종속성을 추적합니다. 비동기 콜백을 사용하는 경우 첫 번째 대기가 제대로 작동하기 전에 액세스된 속성만 추적됩니다.

시계 대 watchEffect

watch와 watchEffect 모두 부작용이 있는 콜백을 반응적으로 실행할 수 있습니다. 이들 사이의 주요 차이점은 반응적 종속성을 추적하는 방식입니다.

watch는 명시적으로 청취되는 데이터 소스만 추적합니다. 콜백에서 액세스된 항목은 추적하지 않습니다. 또한 콜백은 데이터 소스가 실제로 변경될 때만 실행됩니다. watch는 부작용이 발생할 때 종속성 추적을 방지하므로 콜백 함수가 트리거되는 시점을 보다 정확하게 제어할 수 있습니다.

watchEffect는 부작용이 발생하는 동안 종속성을 추적합니다. 동기화 중에 액세스 가능한 모든 반응 속성을 자동으로 추적합니다. 이는 더 편리하고 코드가 더 깔끔한 경향이 있지만 때로는 반응적 종속성이 덜 명확합니다.

콜백 트리거 시간

반응 상태를 변경하면 Vue 구성 요소 업데이트와 리스너 콜백이 모두 트리거될 수 있습니다.

기본적으로 사용자가 만든 리스너 콜백은 Vue 구성 요소가 업데이트되기 전에 호출됩니다. 이는 리스너 콜백에서 액세스하는 DOM이 Vue에 의해 업데이트되기 전의 상태가 됨을 의미합니다.

리스너 콜백에서 Vue에 의해 업데이트된 후 DOM에 액세스할 수 있으려면 플러시: 'post' 옵션을 지정해야 합니다.

watch(source, callback, {
    
    
  flush: 'post'
})

watchEffect(callback, {
    
    
  flush: 'post'
})

새로 고침 후 watchEffect()에는 watchPostEffect()라는 더 편리한 별칭이 있습니다.

import {
    
     watchPostEffect } from 'vue'

watchPostEffect(() => {
    
    
  /* 在 Vue 更新后执行 */
})

리스너 중지

setup()의 <script setup>동기화 문을 사용하여 생성된 리스너는 호스트 구성 요소 인스턴스에 자동으로 바인딩되고 호스트 구성 요소가 제거되면 자동으로 중지됩니다. 따라서 대부분의 경우 리스너 중지에 대해 걱정할 필요가 없습니다.

중요한 점은 리스너가 동기 문으로 생성되어야 한다는 것입니다. 비동기 콜백으로 리스너를 생성하면 현재 구성 요소에 바인딩되지 않으며 메모리 누수를 방지하기 위해 수동으로 중지해야 합니다. 다음 예와 같습니다.

<script setup>
import {
    
     watchEffect } from 'vue'

// 它会自动停止
watchEffect(() => {
    
    })

// ...这个则不会!
setTimeout(() => {
    
    
  watchEffect(() => {
    
    })
}, 100)
</script>

리스너를 수동으로 중지하려면 watch 또는 watchEffect에서 반환된 함수를 호출하세요.

const unwatch = watchEffect(() => {
    
    })

// ...当该侦听器不再需要时
unwatch()

리스너를 비동기식으로 생성해야 하는 상황은 거의 없으므로 가능하면 동기식으로 생성하도록 선택하세요. 일부 비동기 데이터를 기다려야 하는 경우 조건부 수신 논리를 사용할 수 있습니다.

// 需要异步请求得到的数据
const data = ref(null)

watchEffect(() => {
    
    
  if (data.value) {
    
    
    // 数据加载后执行某些操作...
  }
})

Supongo que te gusta

Origin blog.csdn.net/weixin_43361722/article/details/129888215
Recomendado
Clasificación