refactor: use more efficient useComputed() implementation

This commit is contained in:
Evan You 2018-10-30 01:10:03 -04:00
parent f9e3e38fdb
commit 8602b61efb
4 changed files with 18 additions and 15 deletions

View File

@ -1,12 +1,15 @@
import { autorun } from './index' import { autorun } from './index'
import { Autorun, activeAutorunStack } from './autorun' import { Autorun, activeAutorunStack } from './autorun'
export interface ComputedGetter { export interface ComputedGetter<T = any> {
(): any (): T
runner: Autorun runner: Autorun
} }
export function computed(getter: Function, context?: any): ComputedGetter { export function computed<T, C = null>(
getter: (this: C, ctx: C) => T,
context?: C
): ComputedGetter<T> {
let dirty: boolean = true let dirty: boolean = true
let value: any = undefined let value: any = undefined
const runner = autorun(() => getter.call(context, context), { const runner = autorun(() => getter.call(context, context), {

View File

@ -3,6 +3,8 @@ import { computed, stop, ComputedGetter } from '@vue/observer'
import { ComponentInstance } from './component' import { ComponentInstance } from './component'
import { ComponentComputedOptions } from './componentOptions' import { ComponentComputedOptions } from './componentOptions'
export type ComputedHandles = Record<string, ComputedGetter>
export function initializeComputed( export function initializeComputed(
instance: ComponentInstance, instance: ComponentInstance,
computedOptions: ComponentComputedOptions | undefined computedOptions: ComponentComputedOptions | undefined
@ -10,10 +12,7 @@ export function initializeComputed(
if (!computedOptions) { if (!computedOptions) {
return return
} }
const handles: Record< const handles: ComputedHandles = (instance._computedGetters = {})
string,
ComputedGetter
> = (instance._computedGetters = {})
const proxy = instance.$proxy const proxy = instance.$proxy
for (const key in computedOptions) { for (const key in computedOptions) {
const option = computedOptions[key] const option = computedOptions[key]

View File

@ -43,7 +43,8 @@ const renderProxyHandlers = {
} else if (key[0] !== '_') { } else if (key[0] !== '_') {
if (__DEV__ && isRendering && !(key in target)) { if (__DEV__ && isRendering && !(key in target)) {
warn( warn(
`property "${key}" was accessed during render but does not exist on instance.` `property "${key}" was accessed during render but does not exist ` +
`on instance.`
) )
} }
const value = Reflect.get(target, key, receiver) const value = Reflect.get(target, key, receiver)

View File

@ -1,7 +1,7 @@
import { ComponentInstance, FunctionalComponent, Component } from '../component' import { ComponentInstance, FunctionalComponent, Component } from '../component'
import { mergeLifecycleHooks, Data, WatchOptions } from '../componentOptions' import { mergeLifecycleHooks, Data, WatchOptions } from '../componentOptions'
import { VNode, Slots } from '../vdom' import { VNode, Slots } from '../vdom'
import { observable, computed, stop, ComputedGetter } from '@vue/observer' import { observable, computed } from '@vue/observer'
import { setupWatcher } from '../componentWatch' import { setupWatcher } from '../componentWatch'
type RawEffect = () => (() => void) | void type RawEffect = () => (() => void) | void
@ -191,14 +191,14 @@ export function useWatch<T>(
} }
export function useComputed<T>(getter: () => T): T { export function useComputed<T>(getter: () => T): T {
const computedRef = useRef() ensureCurrentInstance()
useUnmounted(() => { const id = `__hooksComputed${++callIndex}`
stop((computedRef.current as ComputedGetter).runner) const instance = currentInstance as ComponentInstance
}) const handles = instance._computedGetters || (instance._computedGetters = {})
if (isMounting) { if (isMounting) {
computedRef.current = computed(getter) handles[id] = computed(getter)
} }
return (computedRef.current as ComputedGetter)() return handles[id]()
} }
export function withHooks(render: FunctionalComponent): new () => Component { export function withHooks(render: FunctionalComponent): new () => Component {