diff --git a/packages/runtime-core/__tests__/hooks.spec.ts b/packages/runtime-core/__tests__/hooks.spec.ts
deleted file mode 100644
index e46e5cfa..00000000
--- a/packages/runtime-core/__tests__/hooks.spec.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { useState, h, nextTick, useEffect, Component } from '../src'
-import { renderInstance, serialize, triggerEvent } from '@vue/runtime-test'
-
-describe('hooks', () => {
- it('useState', async () => {
- class Counter extends Component {
- render() {
- const [count, setCount] = useState(0)
- return h(
- 'div',
- {
- onClick: () => {
- setCount(count + 1)
- }
- },
- count
- )
- }
- }
-
- const counter = await renderInstance(Counter)
- expect(serialize(counter.$el)).toBe(`
0
`)
-
- triggerEvent(counter.$el, 'click')
- await nextTick()
- expect(serialize(counter.$el)).toBe(`1
`)
- })
-
- it('should be usable via hooks() method', async () => {
- class Counter extends Component {
- hooks() {
- const [count, setCount] = useState(0)
- return {
- count,
- setCount
- }
- }
- render() {
- const { count, setCount } = this as any
- return h(
- 'div',
- {
- onClick: () => {
- setCount(count + 1)
- }
- },
- count
- )
- }
- }
-
- const counter = await renderInstance(Counter)
- expect(serialize(counter.$el)).toBe(`0
`)
-
- triggerEvent(counter.$el, 'click')
- await nextTick()
- expect(serialize(counter.$el)).toBe(`1
`)
- })
-
- it('useEffect', async () => {
- let effect = -1
-
- class Counter extends Component {
- render() {
- const [count, setCount] = useState(0)
- useEffect(() => {
- effect = count
- })
- return h(
- 'div',
- {
- onClick: () => {
- setCount(count + 1)
- }
- },
- count
- )
- }
- }
-
- const counter = await renderInstance(Counter)
- expect(effect).toBe(0)
- triggerEvent(counter.$el, 'click')
- await nextTick()
- expect(effect).toBe(1)
- })
-
- it('useEffect with empty keys', async () => {
- // TODO
- })
-
- it('useEffect with keys', async () => {
- // TODO
- })
-
- it('useData', () => {
- // TODO
- })
-
- it('useMounted/useUnmounted/useUpdated', () => {
- // TODO
- })
-
- it('useWatch', () => {
- // TODO
- })
-
- it('useComputed', () => {
- // TODO
- })
-})
diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts
index 4cfb1569..83d86552 100644
--- a/packages/runtime-core/src/component.ts
+++ b/packages/runtime-core/src/component.ts
@@ -45,7 +45,6 @@ interface PublicInstanceMethods {
export interface APIMethods {
data(): Partial
- hooks(): any
render(props: Readonly, slots: Slots, attrs: Data, parentVNode: VNode): any
}
@@ -136,7 +135,6 @@ class InternalComponent implements PublicInstanceMethods {
_queueJob: ((fn: () => void) => void) | null = null
_isVue: boolean = true
_inactiveRoot: boolean = false
- _hookProps: any = null
constructor(props?: object) {
if (props === void 0) {
diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts
index 97e7db15..08112569 100644
--- a/packages/runtime-core/src/componentOptions.ts
+++ b/packages/runtime-core/src/componentOptions.ts
@@ -90,7 +90,6 @@ type ReservedKeys = { [K in keyof (APIMethods & LifecycleMethods)]: 1 }
export const reservedMethods: ReservedKeys = {
data: 1,
render: 1,
- hooks: 1,
beforeCreate: 1,
created: 1,
beforeMount: 1,
diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts
index 0698795d..01871522 100644
--- a/packages/runtime-core/src/componentProxy.ts
+++ b/packages/runtime-core/src/componentProxy.ts
@@ -1,9 +1,8 @@
import { ComponentInstance } from './component'
import { isFunction, isReservedKey } from '@vue/shared'
-import { warn } from './warning'
import { isRendering } from './componentRenderUtils'
-import { isObservable } from '@vue/observer'
import { reservedMethods } from './componentOptions'
+import { warn } from './warning'
const bindCache = new WeakMap()
@@ -37,9 +36,6 @@ const renderProxyHandlers = {
) {
// computed
return i[key]()
- } else if ((i = target._hookProps) !== null && i.hasOwnProperty(key)) {
- // hooks injections
- return i[key]
} else if (key[0] !== '_') {
if (
__DEV__ &&
@@ -81,16 +77,6 @@ const renderProxyHandlers = {
if ((i = target._rawData) !== null && i.hasOwnProperty(key)) {
target.$data[key] = value
return true
- } else if ((i = target._hookProps) !== null && i.hasOwnProperty(key)) {
- if (__DEV__ && !isObservable(i)) {
- warn(
- `attempting to mutate a property returned from hooks(), but the ` +
- `value is not observable.`
- )
- }
- // this enables returning observable objects from hooks()
- i[key] = value
- return true
} else {
return Reflect.set(target, key, value, receiver)
}
diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts
index 50b5508c..07588600 100644
--- a/packages/runtime-core/src/componentRenderUtils.ts
+++ b/packages/runtime-core/src/componentRenderUtils.ts
@@ -4,26 +4,13 @@ import { resolveProps } from './componentProps'
import { handleError, ErrorTypes } from './errorHandling'
import { VNodeFlags, ChildrenFlags } from './flags'
import { EMPTY_OBJ, isArray, isObject } from '@vue/shared'
-import { setCurrentInstance, unsetCurrentInstance } from './experimental/hooks'
export let isRendering = false
export function renderInstanceRoot(instance: ComponentInstance): VNode {
let vnode
- const {
- $options: { hooks },
- render,
- $proxy,
- $props,
- $slots,
- $attrs,
- $parentVNode
- } = instance
+ const { render, $proxy, $props, $slots, $attrs, $parentVNode } = instance
try {
- setCurrentInstance(instance)
- if (hooks) {
- instance._hookProps = hooks.call($proxy, $props) || null
- }
if (__DEV__) {
isRendering = true
}
@@ -31,7 +18,6 @@ export function renderInstanceRoot(instance: ComponentInstance): VNode {
if (__DEV__) {
isRendering = false
}
- unsetCurrentInstance()
} catch (err) {
handleError(err, instance, ErrorTypes.RENDER)
}
diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts
index 38ecc854..d92557cf 100644
--- a/packages/runtime-core/src/createRenderer.ts
+++ b/packages/runtime-core/src/createRenderer.ts
@@ -1258,7 +1258,7 @@ export function createRenderer(options: RendererOptions) {
const {
$proxy,
- $options: { beforeMount, renderTracked, renderTriggered }
+ $options: { beforeMount, mounted, renderTracked, renderTriggered }
} = instance
instance.$forceUpdate = () => {
@@ -1318,9 +1318,6 @@ export function createRenderer(options: RendererOptions) {
if (vnode.ref) {
vnode.ref($proxy)
}
- // retrieve mounted value after initial render so that we get
- // to inject effects in hooks
- const { mounted } = instance.$options
if (mounted) {
callLifecycleHookWithHandler(mounted, $proxy, ErrorTypes.MOUNTED)
}
diff --git a/packages/runtime-core/src/experimental/hooks.ts b/packages/runtime-core/src/experimental/hooks.ts
deleted file mode 100644
index f667b5d2..00000000
--- a/packages/runtime-core/src/experimental/hooks.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import { ComponentInstance } from '../component'
-import { mergeLifecycleHooks, WatchOptions } from '../componentOptions'
-import { observable, computed } from '@vue/observer'
-import { setupWatcher } from '../componentWatch'
-
-type RawEffect = () => (() => void) | void
-
-type Effect = RawEffect & {
- current?: RawEffect | null | void
-}
-
-type EffectRecord = {
- effect: Effect
- cleanup: Effect
- deps: any[] | void
-}
-
-type Ref = { current: T }
-
-type HookState = {
- state: any
- effects: Record
- refs: Record>
-}
-
-let currentInstance: ComponentInstance | null = null
-let isMounting: boolean = false
-let callIndex: number = 0
-
-const hooksStateMap = new WeakMap()
-
-export function setCurrentInstance(instance: ComponentInstance) {
- currentInstance = instance
- isMounting = !currentInstance._mounted
- callIndex = 0
-}
-
-export function unsetCurrentInstance() {
- currentInstance = null
-}
-
-function ensureCurrentInstance() {
- if (!currentInstance) {
- throw new Error(
- `invalid hooks call` +
- (__DEV__
- ? `. Hooks can only be called in one of the following: ` +
- `render(), hooks(), or withHooks().`
- : ``)
- )
- }
-}
-
-function getCurrentHookState(): HookState {
- ensureCurrentInstance()
- let hookState = hooksStateMap.get(currentInstance as ComponentInstance)
- if (!hookState) {
- hookState = {
- state: observable({}),
- effects: {},
- refs: {}
- }
- hooksStateMap.set(currentInstance as ComponentInstance, hookState)
- }
- return hookState
-}
-
-// React compatible hooks ------------------------------------------------------
-
-export function useState(initial: T): [T, (newValue: T) => void] {
- const id = ++callIndex
- const { state } = getCurrentHookState()
- const set = (newValue: any) => {
- state[id] = newValue
- }
- if (isMounting) {
- set(initial)
- }
- return [state[id], set]
-}
-
-export function useEffect(rawEffect: Effect, deps?: any[]) {
- const id = ++callIndex
- if (isMounting) {
- const cleanup: Effect = () => {
- const { current } = cleanup
- if (current) {
- current()
- cleanup.current = null
- }
- }
- const effect: Effect = () => {
- const { current } = effect
- if (current) {
- cleanup.current = current()
- effect.current = null
- }
- }
- effect.current = rawEffect
- getCurrentHookState().effects[id] = {
- effect,
- cleanup,
- deps
- }
-
- injectEffect(currentInstance as ComponentInstance, 'mounted', effect)
- injectEffect(currentInstance as ComponentInstance, 'unmounted', cleanup)
- if (!deps || deps.length !== 0) {
- injectEffect(currentInstance as ComponentInstance, 'updated', effect)
- }
- } else {
- const record = getCurrentHookState().effects[id]
- const { effect, cleanup, deps: prevDeps = [] } = record
- record.deps = deps
- if (!deps || hasDepsChanged(deps, prevDeps)) {
- cleanup()
- effect.current = rawEffect
- }
- }
-}
-
-function hasDepsChanged(deps: any[], prevDeps: any[]): boolean {
- if (deps.length !== prevDeps.length) {
- return true
- }
- for (let i = 0; i < deps.length; i++) {
- if (deps[i] !== prevDeps[i]) {
- return true
- }
- }
- return false
-}
-
-function injectEffect(
- instance: ComponentInstance,
- key: string,
- effect: Effect
-) {
- const existing = instance.$options[key]
- ;(instance.$options as any)[key] = existing
- ? mergeLifecycleHooks(existing, effect)
- : effect
-}
-
-export function useRef(initial?: T): Ref {
- const id = ++callIndex
- const { refs } = getCurrentHookState()
- return isMounting ? (refs[id] = { current: initial }) : refs[id]
-}
-
-// Vue API hooks ---------------------------------------------------------------
-
-export function useData(initial: T): T {
- const id = ++callIndex
- const { state } = getCurrentHookState()
- if (isMounting) {
- state[id] = initial
- }
- return state[id]
-}
-
-export function useMounted(fn: () => void) {
- useEffect(fn, [])
-}
-
-export function useUnmounted(fn: () => void) {
- useEffect(() => fn, [])
-}
-
-export function useUpdated(fn: () => void, deps?: any[]) {
- const isMount = useRef(true)
- useEffect(() => {
- if (isMount.current) {
- isMount.current = false
- } else {
- return fn()
- }
- }, deps)
-}
-
-export function useWatch(
- getter: () => T,
- cb: (val: T, oldVal: T) => void,
- options?: WatchOptions
-) {
- ensureCurrentInstance()
- if (isMounting) {
- setupWatcher(currentInstance as ComponentInstance, getter, cb, options)
- }
-}
-
-export function useComputed(getter: () => T): T {
- ensureCurrentInstance()
- const id = `__hooksComputed${++callIndex}`
- const instance = currentInstance as ComponentInstance
- const handles = instance._computedGetters || (instance._computedGetters = {})
- if (isMounting) {
- handles[id] = computed(getter)
- }
- return handles[id]()
-}
diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts
index 56f9a487..078e3195 100644
--- a/packages/runtime-core/src/index.ts
+++ b/packages/runtime-core/src/index.ts
@@ -32,19 +32,6 @@ export { mixins } from './optional/mixins'
export { EventEmitter } from './optional/eventEmitter'
export { memoize } from './optional/memoize'
-// Experimental APIs
-export {
- useState,
- useEffect,
- useRef,
- useData,
- useWatch,
- useComputed,
- useMounted,
- useUnmounted,
- useUpdated
-} from './experimental/hooks'
-
// flags & types
export { ComponentType, ComponentClass, FunctionalComponent } from './component'
export { VNodeFlags, ChildrenFlags } from './flags'