feat(runtime-core): add watchEffect API
BREAKING CHANGE: replae `watch(fn, options?)` with `watchEffect` The `watch(fn, options?)` signature has been replaced by the new `watchEffect` API, which has the same usage and behavior. `watch` now only supports the `watch(source, cb, options?)` signautre.
This commit is contained in:
parent
b36a76fe23
commit
99a2e18c97
@ -6,7 +6,7 @@ import {
|
||||
render,
|
||||
serializeInner,
|
||||
nextTick,
|
||||
watch,
|
||||
watchEffect,
|
||||
defineComponent,
|
||||
triggerEvent,
|
||||
TestElement
|
||||
@ -55,7 +55,7 @@ describe('api: setup context', () => {
|
||||
|
||||
const Child = defineComponent({
|
||||
setup(props: { count: number }) {
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
dummy = props.count
|
||||
})
|
||||
return () => h('div', props.count)
|
||||
@ -88,7 +88,7 @@ describe('api: setup context', () => {
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
dummy = props.count
|
||||
})
|
||||
return () => h('div', props.count)
|
||||
|
@ -1,4 +1,12 @@
|
||||
import { watch, reactive, computed, nextTick, ref, h } from '../src/index'
|
||||
import {
|
||||
watch,
|
||||
watchEffect,
|
||||
reactive,
|
||||
computed,
|
||||
nextTick,
|
||||
ref,
|
||||
h
|
||||
} from '../src/index'
|
||||
import { render, nodeOps, serializeInner } from '@vue/runtime-test'
|
||||
import {
|
||||
ITERATE_KEY,
|
||||
@ -13,10 +21,10 @@ import { mockWarn } from '@vue/shared'
|
||||
describe('api: watch', () => {
|
||||
mockWarn()
|
||||
|
||||
it('watch(effect)', async () => {
|
||||
it('effect', async () => {
|
||||
const state = reactive({ count: 0 })
|
||||
let dummy
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
dummy = state.count
|
||||
})
|
||||
expect(dummy).toBe(0)
|
||||
@ -117,10 +125,10 @@ describe('api: watch', () => {
|
||||
expect(dummy).toMatchObject([[2, true], [1, false]])
|
||||
})
|
||||
|
||||
it('stopping the watcher', async () => {
|
||||
it('stopping the watcher (effect)', async () => {
|
||||
const state = reactive({ count: 0 })
|
||||
let dummy
|
||||
const stop = watch(() => {
|
||||
const stop = watchEffect(() => {
|
||||
dummy = state.count
|
||||
})
|
||||
expect(dummy).toBe(0)
|
||||
@ -132,11 +140,32 @@ describe('api: watch', () => {
|
||||
expect(dummy).toBe(0)
|
||||
})
|
||||
|
||||
it('stopping the watcher (with source)', async () => {
|
||||
const state = reactive({ count: 0 })
|
||||
let dummy
|
||||
const stop = watch(
|
||||
() => state.count,
|
||||
count => {
|
||||
dummy = count
|
||||
}
|
||||
)
|
||||
|
||||
state.count++
|
||||
await nextTick()
|
||||
expect(dummy).toBe(1)
|
||||
|
||||
stop()
|
||||
state.count++
|
||||
await nextTick()
|
||||
// should not update
|
||||
expect(dummy).toBe(1)
|
||||
})
|
||||
|
||||
it('cleanup registration (effect)', async () => {
|
||||
const state = reactive({ count: 0 })
|
||||
const cleanup = jest.fn()
|
||||
let dummy
|
||||
const stop = watch(onCleanup => {
|
||||
const stop = watchEffect(onCleanup => {
|
||||
onCleanup(cleanup)
|
||||
dummy = state.count
|
||||
})
|
||||
@ -187,7 +216,7 @@ describe('api: watch', () => {
|
||||
|
||||
const Comp = {
|
||||
setup() {
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
assertion(count.value)
|
||||
})
|
||||
return () => count.value
|
||||
@ -221,7 +250,7 @@ describe('api: watch', () => {
|
||||
|
||||
const Comp = {
|
||||
setup() {
|
||||
watch(
|
||||
watchEffect(
|
||||
() => {
|
||||
assertion(count.value, count2.value)
|
||||
},
|
||||
@ -263,7 +292,7 @@ describe('api: watch', () => {
|
||||
|
||||
const Comp = {
|
||||
setup() {
|
||||
watch(
|
||||
watchEffect(
|
||||
() => {
|
||||
assertion(count.value)
|
||||
},
|
||||
@ -363,14 +392,14 @@ describe('api: watch', () => {
|
||||
expect(spy).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
it('warn immediate option when using effect signature', async () => {
|
||||
it('warn immediate option when using effect', async () => {
|
||||
const count = ref(0)
|
||||
let dummy
|
||||
// @ts-ignore
|
||||
watch(
|
||||
watchEffect(
|
||||
() => {
|
||||
dummy = count.value
|
||||
},
|
||||
// @ts-ignore
|
||||
{ immediate: false }
|
||||
)
|
||||
expect(dummy).toBe(0)
|
||||
@ -388,7 +417,7 @@ describe('api: watch', () => {
|
||||
events.push(e)
|
||||
})
|
||||
const obj = reactive({ foo: 1, bar: 2 })
|
||||
watch(
|
||||
watchEffect(
|
||||
() => {
|
||||
dummy = [obj.foo, 'bar' in obj, Object.keys(obj)]
|
||||
},
|
||||
@ -423,7 +452,7 @@ describe('api: watch', () => {
|
||||
events.push(e)
|
||||
})
|
||||
const obj = reactive({ foo: 1 })
|
||||
watch(
|
||||
watchEffect(
|
||||
() => {
|
||||
dummy = obj.foo
|
||||
},
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
nextTick,
|
||||
onMounted,
|
||||
watch,
|
||||
watchEffect,
|
||||
onUnmounted,
|
||||
onErrorCaptured
|
||||
} from '@vue/runtime-test'
|
||||
@ -163,7 +164,7 @@ describe('Suspense', () => {
|
||||
// extra tick needed for Node 12+
|
||||
deps.push(p.then(() => Promise.resolve()))
|
||||
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
calls.push('immediate effect')
|
||||
})
|
||||
|
||||
@ -265,7 +266,7 @@ describe('Suspense', () => {
|
||||
const p = new Promise(r => setTimeout(r, 1))
|
||||
deps.push(p)
|
||||
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
calls.push('immediate effect')
|
||||
})
|
||||
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
watch,
|
||||
ref,
|
||||
nextTick,
|
||||
defineComponent
|
||||
defineComponent,
|
||||
watchEffect
|
||||
} from '@vue/runtime-test'
|
||||
import { setErrorRecovery } from '../src/errorHandling'
|
||||
import { mockWarn } from '@vue/shared'
|
||||
@ -241,7 +242,7 @@ describe('error handling', () => {
|
||||
expect(fn).toHaveBeenCalledWith(err, 'ref function')
|
||||
})
|
||||
|
||||
test('in watch (effect)', () => {
|
||||
test('in effect', () => {
|
||||
const err = new Error('foo')
|
||||
const fn = jest.fn()
|
||||
|
||||
@ -257,7 +258,7 @@ describe('error handling', () => {
|
||||
|
||||
const Child = {
|
||||
setup() {
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
throw err
|
||||
})
|
||||
return () => null
|
||||
@ -268,7 +269,7 @@ describe('error handling', () => {
|
||||
expect(fn).toHaveBeenCalledWith(err, 'watcher callback')
|
||||
})
|
||||
|
||||
test('in watch (getter)', () => {
|
||||
test('in watch getter', () => {
|
||||
const err = new Error('foo')
|
||||
const fn = jest.fn()
|
||||
|
||||
@ -298,7 +299,7 @@ describe('error handling', () => {
|
||||
expect(fn).toHaveBeenCalledWith(err, 'watcher getter')
|
||||
})
|
||||
|
||||
test('in watch (callback)', async () => {
|
||||
test('in watch callback', async () => {
|
||||
const err = new Error('foo')
|
||||
const fn = jest.fn()
|
||||
|
||||
@ -332,7 +333,7 @@ describe('error handling', () => {
|
||||
expect(fn).toHaveBeenCalledWith(err, 'watcher callback')
|
||||
})
|
||||
|
||||
test('in watch cleanup', async () => {
|
||||
test('in effect cleanup', async () => {
|
||||
const err = new Error('foo')
|
||||
const count = ref(0)
|
||||
const fn = jest.fn()
|
||||
@ -349,7 +350,7 @@ describe('error handling', () => {
|
||||
|
||||
const Child = {
|
||||
setup() {
|
||||
watch(onCleanup => {
|
||||
watchEffect(onCleanup => {
|
||||
count.value
|
||||
onCleanup(() => {
|
||||
throw err
|
||||
|
@ -71,6 +71,14 @@ export type StopHandle = () => void
|
||||
|
||||
const invoke = (fn: Function) => fn()
|
||||
|
||||
// Simple effect.
|
||||
export function watchEffect(
|
||||
effect: WatchEffect,
|
||||
options?: BaseWatchOptions
|
||||
): StopHandle {
|
||||
return doWatch(effect, null, options)
|
||||
}
|
||||
|
||||
// initial value for watchers to trigger on undefined initial values
|
||||
const INITIAL_WATCHER_VALUE = {}
|
||||
|
||||
@ -110,6 +118,13 @@ export function watch<T = any>(
|
||||
// watch(source, cb)
|
||||
return doWatch(effectOrSource, cbOrOptions, options)
|
||||
} else {
|
||||
// TODO remove this in the next release
|
||||
__DEV__ &&
|
||||
warn(
|
||||
`\`watch(fn, options?)\` signature has been moved to a separate API. ` +
|
||||
`Use \`watchEffect(fn, options?)\` instead. \`watch\` will only ` +
|
||||
`support \`watch(source, cb, options?) signature in the next release.`
|
||||
)
|
||||
// watch(effect)
|
||||
return doWatch(effectOrSource, null, cbOrOptions)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export {
|
||||
markNonReactive
|
||||
} from '@vue/reactivity'
|
||||
export { computed } from './apiComputed'
|
||||
export { watch } from './apiWatch'
|
||||
export { watch, watchEffect } from './apiWatch'
|
||||
export {
|
||||
onBeforeMount,
|
||||
onMounted,
|
||||
|
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const { createApp, ref, watch } = Vue
|
||||
const { createApp, ref, watchEffect } = Vue
|
||||
const API_URL = `https://api.github.com/repos/vuejs/vue-next/commits?per_page=3&sha=`
|
||||
|
||||
const truncate = v => {
|
||||
@ -37,7 +37,7 @@ createApp({
|
||||
const currentBranch = ref('master')
|
||||
const commits = ref(null)
|
||||
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
fetch(`${API_URL}${currentBranch.value}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
@ -53,7 +53,7 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const { createApp, reactive, computed, watch, onMounted, onUnmounted } = Vue
|
||||
const { createApp, reactive, computed, watchEffect, onMounted, onUnmounted } = Vue
|
||||
|
||||
const STORAGE_KEY = 'todos-vuejs-3.x'
|
||||
const todoStorage = {
|
||||
@ -119,7 +119,7 @@ createApp({
|
||||
})
|
||||
})
|
||||
|
||||
watch(() => {
|
||||
watchEffect(() => {
|
||||
todoStorage.save(state.todos)
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user