p로 변경됩니다."/> p로 변경됩니다.">
<script lang="ts" setup> // 接受父组件传递的数据 const props = defineProps({ test: { type: String, default: '' } }) // 使用 watch 侦听 props 中的 test 属性 watch( // 这种写法不会侦听到 props 中 test 的变化 props.test, () => { console.log("侦听成功") } ) watch( // 这种写法会侦听到 props 中 test 的变化 () => props.test, () => { console.log("侦听成功") } ) </script>
watch의 기본 사용법
watch()의 기본값은 lazy listening이며, 이는 listening 소스에서만 발생합니다. 함수는 변경이 있을 때만 실행됩니다
첫 번째 매개변수: 청취 소스는 다음 유형 중 하나일 수 있습니다.
값, ref, 반응형 객체(reactive)를 반환하거나 다음으로 구성되는 함수입니다. 위 유형의 값 배열두 번째 매개변수: 청취 소스가 변경될 때 트리거되는 콜백 함수입니다.
(newValue, oldValue) => { /* code */}
여러 소스를 수신할 때 콜백 함수는 소스 배열의 새 값과 이전 값에 해당하는 두 개의 배열을 허용합니다.
( [ newValue1 , newValue2 ] , [ oldValue1 , oldValue2 ]) => {/* code */}
세 번째 매개변수: 이러한 옵션을 지원할 수 있는 선택적 개체
immediate: 리스너가 깊게 생성되면 콜백이 즉시 트리거됩니다. 소스는 딥 레벨이 플러시로 변경될 때 콜백 함수를 트리거하도록 깊이 탐색을 강제하는 객체입니다. 콜백 함수의 새로 고침 타이밍을 조정합니다. onTrack / onTrigger: 디버그 리스너 종속성
보기 code>의 청취 소스는 위의 4가지 상황만 가능합니다<code>watch
的侦听源只能是上面的4中情况
const obj = reactive({ count: 0 }) // 错误,因为 watch() 中的侦听源是一个 number,最终 source 返回的 getter 函数是一个空,所以就得不到侦听的数据 watch(obj.count, (count) => { console.log(`count is: ${count}`) }) // 正确,主要思想是,将侦听源转化为以上4种类型(转化为getter函数是最简单方便的) watch( () => obj.count, (count) => { console.log(`count is: ${count}`) } )
export function watch<T = any, Immediate extends Readonly<boolean> = false>( source: T | WatchSource<T>, cb: any, options?: WatchOptions<Immediate> ): WatchStopHandle { if (__DEV__ && !isFunction(cb)) { warn( `\`watch(fn, options?)\` signature has been moved to a separate API. ` + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + `supports \`watch(source, cb, options?) signature.` ) } return doWatch(source as any, cb, options) }
从源码中可以看出,watch
接收三个参数:source
侦听源、cb
回调函数、options
侦听配置,最后会返回一个doWatch
function doWatch( source: WatchSource | WatchSource[] | WatchEffect | object, cb: WatchCallback | null, { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ ): WatchStopHandle { // ... // 当前组件实例 const instance = currentInstance // 副作用函数,在初始化effect时使用 let getter: () => any // 强制触发侦听 let forceTrigger = false // 是否为多数据源。 let isMultiSource = false }
doWatch
依然接受三个参数:source
侦听源、cb
回调函数、options
侦听配置
这里着重对侦听源的源码进行分析(source标准化)
如果source
是ref
类型,getter
是个返回source.value
的函数,forceTrigger
取决于source
是否是浅层响应式。
if (isRef(source)) { getter = () => source.value forceTrigger = isShallow(source) }
如果source
是reactive
类型,getter
是个返回source
的函数,并将deep
设置为true
。 当直接侦听一个响应式对象时,侦听器会自动启用深层模式
if (isReactive(source)) { getter = () => source deep = true }
例子
<template> <div class="container"> <h3>obj---{{ obj }}</h3> <button @click="changeName">修改名字</button> <button @click="changeAge">修改年龄</button> </div> </template> <script lang="ts" setup> import { reactive, watch } from "vue"; const obj = reactive({ name: "张三", age: 18, }); const changeName = () => { obj.name += "++"; }; const changeAge = () => { obj.age += 1; }; // obj 中的任一属性变化了,都会被监听到 watch(obj, () => { console.log("变化了"); }); </script>
如果source
是个数组,将isMultiSource
设为true
,forceTrigger
取决于source
是否有reactive
类型的数据,getter
函数中会遍历source
,针对不同类型的source
做不同处理。
if (isArray(source)) { isMultiSource = true forceTrigger = source.some(isReactive) getter = () => source.map(s => { if (isRef(s)) { return s.value } else if (isReactive(s)) { return traverse(s) } else if (isFunction(s)) { return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) } else { __DEV__ && warnInvalidSource(s) } }) }
如果source
是个function
。存在cb
的情况下,getter
函数中会执行source
,这里source
会通过callWithErrorHandling
函数执行,在callWithErrorHandling
中会处理source
执行过程中出现的错误;不存在cb
的话,在getter
中,如果组件已经被卸载了,直接return
,否则判断cleanup
(cleanup
是在watchEffect
中通过onCleanup
注册的清理函数),如果存在cleanup
执行cleanup
,接着执行source
,并返回执行结果。source
会被callWithAsyncErrorHandling
包装,该函数作用会处理source
执行过程中出现的错误,与callWithErrorHandling
不同的是,callWithAsyncErrorHandling
会处理异步错误。
if (isFunction(source)) { if (cb) { getter = () => callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER) } else { // watchEffect getter = () => { // 如果组件实例已经卸载,直接return if (instance && instance.isUnmounted) { return } // 如果清理函数,则执行清理函数 if (cleanup) { cleanup() } // 执行source,传入onCleanup,用来注册清理函数 return callWithAsyncErrorHandling( source, instance, ErrorCodes.WATCH_CALLBACK, [onCleanup] ) } } }
其他情况getter
getter = NOOP __DEV__ && warnInvalidSource(source)3.watch 소스 코드 분석
watch
가 세 가지 매개변수 소스를 받는 것을 소스 코드에서 볼 수 있습니다.
청취 소스, cb
콜백 함수, options
청취 구성, 그리고 마지막으로 doWatch
🎜🎜4.doWatch 소스 코드가 반환됩니다. 분석 🎜rrreee🎜doWatch
는 여전히 source
청취 소스, cb
콜백 함수, options
청취 청취 구성의 세 가지 매개변수를 허용합니다. 🎜🎜여기에서는 청취 소스의 소스 코드 분석에 중점을 둡니다(🎜소스 표준화🎜)🎜source
가 인 경우 ref
유형, getter
는 source.value
를 반환하는 함수입니다. forceTrigger
는 source
여부에 따라 다릅니다. 얕은 반응성입니다. 🎜🎜🎜rrreeesource
가 reactive
유형인 경우 getter
는 source
의 반환 함수를 사용하고 deep
을 true
로 설정하세요. 반응형 객체를 직접 들을 때 리스너는 자동으로 딥 모드를 활성화합니다 🎜🎜🎜rrreee🎜Example🎜rrreeesource
가 배열인 경우 , isMultiSource
를 true
로 설정하세요. forceTrigger
는 source
에 reactive
가 있는지 여부에 따라 달라집니다. > 유형 데이터인 경우 getter
함수는 source
를 순회하고 다양한 유형의 source
에 대해 서로 다른 처리를 수행합니다. 🎜🎜🎜rrreeesource
가 함수
인 경우. cb
가 존재하는 경우 source
는 getter
함수에서 실행되며, 여기서 source
는 callWithErrorHandling함수 실행, <code>source
실행 중 발생하는 오류는 cb
가 없으면 callWithErrorHandling
에서 처리됩니다. >getter , 구성 요소가 제거된 경우 직접 return
하고, 그렇지 않으면 cleanup
을 결정합니다(cleanup
은 watchEffect code> (<code>onCleanup
을 통해 등록된 정리 함수), cleanup
이 있으면 cleanup
을 실행한 후 source를 실행합니다. code> 및 실행 결과를 반환합니다. <code>source
는 callWithAsyncErrorHandling
으로 래핑됩니다. 이 함수는 callWithErrorHandlingsource
실행 중에 발생하는 오류를 처리합니다. /code> 예, callWithAsyncErrorHandling
은 비동기 오류를 처리합니다. 🎜🎜🎜rrreeegetter
에 빈 함수가 할당됩니다🎜🎜🎜rrreee위 내용은 watch를 사용하여 Vue3에서 객체의 속성 값을 모니터링하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!