refactor: rename things

This commit is contained in:
Evan You 2018-11-13 11:03:35 -05:00
parent 0cd8183fbf
commit 80d1eb7480
22 changed files with 423 additions and 414 deletions

View File

@ -1,4 +1,4 @@
import { observable, autorun, unwrap, isObservable } from '../../src' import { observable, effect, unwrap, isObservable } from '../../src'
describe('observer/collections', () => { describe('observer/collections', () => {
describe('Map', () => { describe('Map', () => {
@ -13,7 +13,7 @@ describe('observer/collections', () => {
it('should observe mutations', () => { it('should observe mutations', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => { effect(() => {
dummy = map.get('key') dummy = map.get('key')
}) })
@ -29,7 +29,7 @@ describe('observer/collections', () => {
it('should observe size mutations', () => { it('should observe size mutations', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => (dummy = map.size)) effect(() => (dummy = map.size))
expect(dummy).toBe(0) expect(dummy).toBe(0)
map.set('key1', 'value') map.set('key1', 'value')
@ -44,7 +44,7 @@ describe('observer/collections', () => {
it('should observe for of iteration', () => { it('should observe for of iteration', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
for (let [key, num] of map) { for (let [key, num] of map) {
@ -67,7 +67,7 @@ describe('observer/collections', () => {
it('should observe forEach iteration', () => { it('should observe forEach iteration', () => {
let dummy: any let dummy: any
const map = observable(new Map()) const map = observable(new Map())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
map.forEach((num: any) => (dummy += num)) map.forEach((num: any) => (dummy += num))
}) })
@ -86,7 +86,7 @@ describe('observer/collections', () => {
it('should observe keys iteration', () => { it('should observe keys iteration', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let key of map.keys()) { for (let key of map.keys()) {
dummy += key dummy += key
@ -107,7 +107,7 @@ describe('observer/collections', () => {
it('should observe values iteration', () => { it('should observe values iteration', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let num of map.values()) { for (let num of map.values()) {
dummy += num dummy += num
@ -128,7 +128,7 @@ describe('observer/collections', () => {
it('should observe entries iteration', () => { it('should observe entries iteration', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
for (let [key, num] of map.entries()) { for (let [key, num] of map.entries()) {
@ -151,7 +151,7 @@ describe('observer/collections', () => {
it('should be triggered by clearing', () => { it('should be triggered by clearing', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => (dummy = map.get('key'))) effect(() => (dummy = map.get('key')))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
map.set('key', 3) map.set('key', 3)
@ -163,7 +163,7 @@ describe('observer/collections', () => {
it('should not observe custom property mutations', () => { it('should not observe custom property mutations', () => {
let dummy let dummy
const map: any = observable(new Map()) const map: any = observable(new Map())
autorun(() => (dummy = map.customProp)) effect(() => (dummy = map.customProp))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
map.customProp = 'Hello World' map.customProp = 'Hello World'
@ -174,7 +174,7 @@ describe('observer/collections', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
const mapSpy = jest.fn(() => (dummy = map.get('key'))) const mapSpy = jest.fn(() => (dummy = map.get('key')))
autorun(mapSpy) effect(mapSpy)
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
expect(mapSpy).toHaveBeenCalledTimes(1) expect(mapSpy).toHaveBeenCalledTimes(1)
@ -198,7 +198,7 @@ describe('observer/collections', () => {
it('should not observe raw data', () => { it('should not observe raw data', () => {
let dummy let dummy
const map = observable(new Map()) const map = observable(new Map())
autorun(() => (dummy = unwrap(map).get('key'))) effect(() => (dummy = unwrap(map).get('key')))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
map.set('key', 'Hello') map.set('key', 'Hello')
@ -229,7 +229,7 @@ describe('observer/collections', () => {
const observed = observable(new Map()) const observed = observable(new Map())
observed.set('key', { a: 1 }) observed.set('key', { a: 1 })
let dummy let dummy
autorun(() => { effect(() => {
dummy = observed.get('key').a dummy = observed.get('key').a
}) })
observed.get('key').a = 2 observed.get('key').a = 2
@ -239,7 +239,7 @@ describe('observer/collections', () => {
it('should observe nested values in iterations (forEach)', () => { it('should observe nested values in iterations (forEach)', () => {
const map = observable(new Map([[1, { foo: 1 }]])) const map = observable(new Map([[1, { foo: 1 }]]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
map.forEach(value => { map.forEach(value => {
expect(isObservable(value)).toBe(true) expect(isObservable(value)).toBe(true)
@ -254,7 +254,7 @@ describe('observer/collections', () => {
it('should observe nested values in iterations (values)', () => { it('should observe nested values in iterations (values)', () => {
const map = observable(new Map([[1, { foo: 1 }]])) const map = observable(new Map([[1, { foo: 1 }]]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (const value of map.values()) { for (const value of map.values()) {
expect(isObservable(value)).toBe(true) expect(isObservable(value)).toBe(true)
@ -270,7 +270,7 @@ describe('observer/collections', () => {
const key = {} const key = {}
const map = observable(new Map([[key, { foo: 1 }]])) const map = observable(new Map([[key, { foo: 1 }]]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (const [key, value] of map.entries()) { for (const [key, value] of map.entries()) {
key key
@ -288,7 +288,7 @@ describe('observer/collections', () => {
const key = {} const key = {}
const map = observable(new Map([[key, { foo: 1 }]])) const map = observable(new Map([[key, { foo: 1 }]]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (const [key, value] of map) { for (const [key, value] of map) {
key key

View File

@ -1,4 +1,4 @@
import { observable, autorun, isObservable, unwrap } from '../../src' import { observable, effect, isObservable, unwrap } from '../../src'
describe('observer/collections', () => { describe('observer/collections', () => {
describe('Set', () => { describe('Set', () => {
@ -13,7 +13,7 @@ describe('observer/collections', () => {
it('should observe mutations', () => { it('should observe mutations', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = set.has('value'))) effect(() => (dummy = set.has('value')))
expect(dummy).toBe(false) expect(dummy).toBe(false)
set.add('value') set.add('value')
@ -25,7 +25,7 @@ describe('observer/collections', () => {
it('should observe for of iteration', () => { it('should observe for of iteration', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let num of set) { for (let num of set) {
dummy += num dummy += num
@ -45,7 +45,7 @@ describe('observer/collections', () => {
it('should observe forEach iteration', () => { it('should observe forEach iteration', () => {
let dummy: any let dummy: any
const set = observable(new Set()) const set = observable(new Set())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
set.forEach(num => (dummy += num)) set.forEach(num => (dummy += num))
}) })
@ -63,7 +63,7 @@ describe('observer/collections', () => {
it('should observe values iteration', () => { it('should observe values iteration', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let num of set.values()) { for (let num of set.values()) {
dummy += num dummy += num
@ -83,7 +83,7 @@ describe('observer/collections', () => {
it('should observe keys iteration', () => { it('should observe keys iteration', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let num of set.keys()) { for (let num of set.keys()) {
dummy += num dummy += num
@ -103,7 +103,7 @@ describe('observer/collections', () => {
it('should observe entries iteration', () => { it('should observe entries iteration', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
for (let [key, num] of set.entries()) { for (let [key, num] of set.entries()) {
@ -125,7 +125,7 @@ describe('observer/collections', () => {
it('should be triggered by clearing', () => { it('should be triggered by clearing', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = set.has('key'))) effect(() => (dummy = set.has('key')))
expect(dummy).toBe(false) expect(dummy).toBe(false)
set.add('key') set.add('key')
@ -137,7 +137,7 @@ describe('observer/collections', () => {
it('should not observe custom property mutations', () => { it('should not observe custom property mutations', () => {
let dummy let dummy
const set: any = observable(new Set()) const set: any = observable(new Set())
autorun(() => (dummy = set.customProp)) effect(() => (dummy = set.customProp))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
set.customProp = 'Hello World' set.customProp = 'Hello World'
@ -147,7 +147,7 @@ describe('observer/collections', () => {
it('should observe size mutations', () => { it('should observe size mutations', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = set.size)) effect(() => (dummy = set.size))
expect(dummy).toBe(0) expect(dummy).toBe(0)
set.add('value') set.add('value')
@ -163,7 +163,7 @@ describe('observer/collections', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
const setSpy = jest.fn(() => (dummy = set.has('value'))) const setSpy = jest.fn(() => (dummy = set.has('value')))
autorun(setSpy) effect(setSpy)
expect(dummy).toBe(false) expect(dummy).toBe(false)
expect(setSpy).toHaveBeenCalledTimes(1) expect(setSpy).toHaveBeenCalledTimes(1)
@ -187,7 +187,7 @@ describe('observer/collections', () => {
it('should not observe raw data', () => { it('should not observe raw data', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = unwrap(set).has('value'))) effect(() => (dummy = unwrap(set).has('value')))
expect(dummy).toBe(false) expect(dummy).toBe(false)
set.add('value') set.add('value')
@ -197,7 +197,7 @@ describe('observer/collections', () => {
it('should not observe raw iterations', () => { it('should not observe raw iterations', () => {
let dummy = 0 let dummy = 0
const set = observable(new Set()) const set = observable(new Set())
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let [num] of unwrap(set).entries()) { for (let [num] of unwrap(set).entries()) {
dummy += num dummy += num
@ -227,7 +227,7 @@ describe('observer/collections', () => {
it('should not be triggered by raw mutations', () => { it('should not be triggered by raw mutations', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = set.has('value'))) effect(() => (dummy = set.has('value')))
expect(dummy).toBe(false) expect(dummy).toBe(false)
unwrap(set).add('value') unwrap(set).add('value')
@ -242,7 +242,7 @@ describe('observer/collections', () => {
it('should not observe raw size mutations', () => { it('should not observe raw size mutations', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = unwrap(set).size)) effect(() => (dummy = unwrap(set).size))
expect(dummy).toBe(0) expect(dummy).toBe(0)
set.add('value') set.add('value')
@ -252,7 +252,7 @@ describe('observer/collections', () => {
it('should not be triggered by raw size mutations', () => { it('should not be triggered by raw size mutations', () => {
let dummy let dummy
const set = observable(new Set()) const set = observable(new Set())
autorun(() => (dummy = set.size)) effect(() => (dummy = set.size))
expect(dummy).toBe(0) expect(dummy).toBe(0)
unwrap(set).add('value') unwrap(set).add('value')
@ -264,7 +264,7 @@ describe('observer/collections', () => {
const key = {} const key = {}
const set = observable(new Set()) const set = observable(new Set())
const setSpy = jest.fn(() => (dummy = set.has(key))) const setSpy = jest.fn(() => (dummy = set.has(key)))
autorun(setSpy) effect(setSpy)
expect(dummy).toBe(false) expect(dummy).toBe(false)
expect(setSpy).toHaveBeenCalledTimes(1) expect(setSpy).toHaveBeenCalledTimes(1)
@ -290,7 +290,7 @@ describe('observer/collections', () => {
it('should observe nested values in iterations (forEach)', () => { it('should observe nested values in iterations (forEach)', () => {
const set = observable(new Set([{ foo: 1 }])) const set = observable(new Set([{ foo: 1 }]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
set.forEach(value => { set.forEach(value => {
expect(isObservable(value)).toBe(true) expect(isObservable(value)).toBe(true)
@ -307,7 +307,7 @@ describe('observer/collections', () => {
it('should observe nested values in iterations (values)', () => { it('should observe nested values in iterations (values)', () => {
const set = observable(new Set([{ foo: 1 }])) const set = observable(new Set([{ foo: 1 }]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (const value of set.values()) { for (const value of set.values()) {
expect(isObservable(value)).toBe(true) expect(isObservable(value)).toBe(true)
@ -324,7 +324,7 @@ describe('observer/collections', () => {
it('should observe nested values in iterations (entries)', () => { it('should observe nested values in iterations (entries)', () => {
const set = observable(new Set([{ foo: 1 }])) const set = observable(new Set([{ foo: 1 }]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (const [key, value] of set.entries()) { for (const [key, value] of set.entries()) {
expect(isObservable(key)).toBe(true) expect(isObservable(key)).toBe(true)
@ -342,7 +342,7 @@ describe('observer/collections', () => {
it('should observe nested values in iterations (for...of)', () => { it('should observe nested values in iterations (for...of)', () => {
const set = observable(new Set([{ foo: 1 }])) const set = observable(new Set([{ foo: 1 }]))
let dummy: any let dummy: any
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (const value of set) { for (const value of set) {
expect(isObservable(value)).toBe(true) expect(isObservable(value)).toBe(true)

View File

@ -1,4 +1,4 @@
import { observable, autorun, unwrap, isObservable } from '../../src' import { observable, effect, unwrap, isObservable } from '../../src'
describe('observer/collections', () => { describe('observer/collections', () => {
describe('WeakMap', () => { describe('WeakMap', () => {
@ -14,7 +14,7 @@ describe('observer/collections', () => {
let dummy let dummy
const key = {} const key = {}
const map = observable(new WeakMap()) const map = observable(new WeakMap())
autorun(() => { effect(() => {
dummy = map.get(key) dummy = map.get(key)
}) })
@ -30,7 +30,7 @@ describe('observer/collections', () => {
it('should not observe custom property mutations', () => { it('should not observe custom property mutations', () => {
let dummy let dummy
const map: any = observable(new WeakMap()) const map: any = observable(new WeakMap())
autorun(() => (dummy = map.customProp)) effect(() => (dummy = map.customProp))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
map.customProp = 'Hello World' map.customProp = 'Hello World'
@ -42,7 +42,7 @@ describe('observer/collections', () => {
const key = {} const key = {}
const map = observable(new WeakMap()) const map = observable(new WeakMap())
const mapSpy = jest.fn(() => (dummy = map.get(key))) const mapSpy = jest.fn(() => (dummy = map.get(key)))
autorun(mapSpy) effect(mapSpy)
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
expect(mapSpy).toHaveBeenCalledTimes(1) expect(mapSpy).toHaveBeenCalledTimes(1)
@ -64,7 +64,7 @@ describe('observer/collections', () => {
let dummy let dummy
const key = {} const key = {}
const map = observable(new WeakMap()) const map = observable(new WeakMap())
autorun(() => (dummy = unwrap(map).get(key))) effect(() => (dummy = unwrap(map).get(key)))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
map.set(key, 'Hello') map.set(key, 'Hello')
@ -98,7 +98,7 @@ describe('observer/collections', () => {
const key = {} const key = {}
observed.set(key, { a: 1 }) observed.set(key, { a: 1 })
let dummy let dummy
autorun(() => { effect(() => {
dummy = observed.get(key).a dummy = observed.get(key).a
}) })
observed.get(key).a = 2 observed.get(key).a = 2

View File

@ -1,4 +1,4 @@
import { observable, isObservable, autorun, unwrap } from '../../src' import { observable, isObservable, effect, unwrap } from '../../src'
describe('observer/collections', () => { describe('observer/collections', () => {
describe('WeakSet', () => { describe('WeakSet', () => {
@ -14,7 +14,7 @@ describe('observer/collections', () => {
let dummy let dummy
const value = {} const value = {}
const set = observable(new WeakSet()) const set = observable(new WeakSet())
autorun(() => (dummy = set.has(value))) effect(() => (dummy = set.has(value)))
expect(dummy).toBe(false) expect(dummy).toBe(false)
set.add(value) set.add(value)
@ -26,7 +26,7 @@ describe('observer/collections', () => {
it('should not observe custom property mutations', () => { it('should not observe custom property mutations', () => {
let dummy let dummy
const set: any = observable(new WeakSet()) const set: any = observable(new WeakSet())
autorun(() => (dummy = set.customProp)) effect(() => (dummy = set.customProp))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
set.customProp = 'Hello World' set.customProp = 'Hello World'
@ -38,7 +38,7 @@ describe('observer/collections', () => {
const value = {} const value = {}
const set = observable(new WeakSet()) const set = observable(new WeakSet())
const setSpy = jest.fn(() => (dummy = set.has(value))) const setSpy = jest.fn(() => (dummy = set.has(value)))
autorun(setSpy) effect(setSpy)
expect(dummy).toBe(false) expect(dummy).toBe(false)
expect(setSpy).toHaveBeenCalledTimes(1) expect(setSpy).toHaveBeenCalledTimes(1)
@ -60,7 +60,7 @@ describe('observer/collections', () => {
const value = {} const value = {}
let dummy let dummy
const set = observable(new WeakSet()) const set = observable(new WeakSet())
autorun(() => (dummy = unwrap(set).has(value))) effect(() => (dummy = unwrap(set).has(value)))
expect(dummy).toBe(false) expect(dummy).toBe(false)
set.add(value) set.add(value)
@ -71,7 +71,7 @@ describe('observer/collections', () => {
const value = {} const value = {}
let dummy let dummy
const set = observable(new WeakSet()) const set = observable(new WeakSet())
autorun(() => (dummy = set.has(value))) effect(() => (dummy = set.has(value)))
expect(dummy).toBe(false) expect(dummy).toBe(false)
unwrap(set).add(value) unwrap(set).add(value)

View File

@ -1,4 +1,4 @@
import { computed, observable, autorun, stop } from '../src' import { computed, observable, effect, stop } from '../src'
describe('observer/computed', () => { describe('observer/computed', () => {
it('should return updated value', () => { it('should return updated value', () => {
@ -52,11 +52,11 @@ describe('observer/computed', () => {
expect(callArg).toBe(ctx) expect(callArg).toBe(ctx)
}) })
it('should trigger autorun', () => { it('should trigger effect', () => {
const value: any = observable({}) const value: any = observable({})
const cValue = computed(() => value.foo) const cValue = computed(() => value.foo)
let dummy let dummy
autorun(() => { effect(() => {
dummy = cValue() dummy = cValue()
}) })
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
@ -75,7 +75,7 @@ describe('observer/computed', () => {
expect(c1()).toBe(1) expect(c1()).toBe(1)
}) })
it('should trigger autorun when chained', () => { it('should trigger effect when chained', () => {
const value: any = observable({ foo: 0 }) const value: any = observable({ foo: 0 })
const getter1 = jest.fn(() => value.foo) const getter1 = jest.fn(() => value.foo)
const getter2 = jest.fn(() => { const getter2 = jest.fn(() => {
@ -85,7 +85,7 @@ describe('observer/computed', () => {
const c2 = computed(getter2) const c2 = computed(getter2)
let dummy let dummy
autorun(() => { effect(() => {
dummy = c2() dummy = c2()
}) })
expect(dummy).toBe(1) expect(dummy).toBe(1)
@ -98,7 +98,7 @@ describe('observer/computed', () => {
expect(getter2).toHaveBeenCalledTimes(2) expect(getter2).toHaveBeenCalledTimes(2)
}) })
it('should trigger autorun when chained (mixed invocations)', () => { it('should trigger effect when chained (mixed invocations)', () => {
const value: any = observable({ foo: 0 }) const value: any = observable({ foo: 0 })
const getter1 = jest.fn(() => value.foo) const getter1 = jest.fn(() => value.foo)
const getter2 = jest.fn(() => { const getter2 = jest.fn(() => {
@ -108,7 +108,7 @@ describe('observer/computed', () => {
const c2 = computed(getter2) const c2 = computed(getter2)
let dummy let dummy
autorun(() => { effect(() => {
dummy = c1() + c2() dummy = c1() + c2()
}) })
expect(dummy).toBe(1) expect(dummy).toBe(1)
@ -126,13 +126,13 @@ describe('observer/computed', () => {
const value: any = observable({}) const value: any = observable({})
const cValue = computed(() => value.foo) const cValue = computed(() => value.foo)
let dummy let dummy
autorun(() => { effect(() => {
dummy = cValue() dummy = cValue()
}) })
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
value.foo = 1 value.foo = 1
expect(dummy).toBe(1) expect(dummy).toBe(1)
stop(cValue.runner) stop(cValue.effect)
value.foo = 2 value.foo = 2
expect(dummy).toBe(1) expect(dummy).toBe(1)
}) })

View File

@ -1,25 +1,25 @@
import { import {
observable, observable,
autorun, effect,
stop, stop,
unwrap, unwrap,
OperationTypes, OperationTypes,
DebuggerEvent, DebuggerEvent,
markNonReactive markNonReactive
} from '../src/index' } from '../src/index'
import { ITERATE_KEY } from '../src/autorun' import { ITERATE_KEY } from '../src/effect'
describe('observer/autorun', () => { describe('observer/effect', () => {
it('should run the passed function once (wrapped by a autorun)', () => { it('should run the passed function once (wrapped by a effect)', () => {
const fnSpy = jest.fn(() => {}) const fnSpy = jest.fn(() => {})
autorun(fnSpy) effect(fnSpy)
expect(fnSpy).toHaveBeenCalledTimes(1) expect(fnSpy).toHaveBeenCalledTimes(1)
}) })
it('should observe basic properties', () => { it('should observe basic properties', () => {
let dummy let dummy
const counter = observable({ num: 0 }) const counter = observable({ num: 0 })
autorun(() => (dummy = counter.num)) effect(() => (dummy = counter.num))
expect(dummy).toBe(0) expect(dummy).toBe(0)
counter.num = 7 counter.num = 7
@ -29,18 +29,18 @@ describe('observer/autorun', () => {
it('should observe multiple properties', () => { it('should observe multiple properties', () => {
let dummy let dummy
const counter = observable({ num1: 0, num2: 0 }) const counter = observable({ num1: 0, num2: 0 })
autorun(() => (dummy = counter.num1 + counter.num1 + counter.num2)) effect(() => (dummy = counter.num1 + counter.num1 + counter.num2))
expect(dummy).toBe(0) expect(dummy).toBe(0)
counter.num1 = counter.num2 = 7 counter.num1 = counter.num2 = 7
expect(dummy).toBe(21) expect(dummy).toBe(21)
}) })
it('should handle multiple autoruns', () => { it('should handle multiple effects', () => {
let dummy1, dummy2 let dummy1, dummy2
const counter = observable({ num: 0 }) const counter = observable({ num: 0 })
autorun(() => (dummy1 = counter.num)) effect(() => (dummy1 = counter.num))
autorun(() => (dummy2 = counter.num)) effect(() => (dummy2 = counter.num))
expect(dummy1).toBe(0) expect(dummy1).toBe(0)
expect(dummy2).toBe(0) expect(dummy2).toBe(0)
@ -52,7 +52,7 @@ describe('observer/autorun', () => {
it('should observe nested properties', () => { it('should observe nested properties', () => {
let dummy let dummy
const counter = observable({ nested: { num: 0 } }) const counter = observable({ nested: { num: 0 } })
autorun(() => (dummy = counter.nested.num)) effect(() => (dummy = counter.nested.num))
expect(dummy).toBe(0) expect(dummy).toBe(0)
counter.nested.num = 8 counter.nested.num = 8
@ -62,7 +62,7 @@ describe('observer/autorun', () => {
it('should observe delete operations', () => { it('should observe delete operations', () => {
let dummy let dummy
const obj = observable({ prop: 'value' }) const obj = observable({ prop: 'value' })
autorun(() => (dummy = obj.prop)) effect(() => (dummy = obj.prop))
expect(dummy).toBe('value') expect(dummy).toBe('value')
delete obj.prop delete obj.prop
@ -72,7 +72,7 @@ describe('observer/autorun', () => {
it('should observe has operations', () => { it('should observe has operations', () => {
let dummy let dummy
const obj: any = observable({ prop: 'value' }) const obj: any = observable({ prop: 'value' })
autorun(() => (dummy = 'prop' in obj)) effect(() => (dummy = 'prop' in obj))
expect(dummy).toBe(true) expect(dummy).toBe(true)
delete obj.prop delete obj.prop
@ -86,7 +86,7 @@ describe('observer/autorun', () => {
const counter = observable({ num: 0 }) const counter = observable({ num: 0 })
const parentCounter = observable({ num: 2 }) const parentCounter = observable({ num: 2 })
Object.setPrototypeOf(counter, parentCounter) Object.setPrototypeOf(counter, parentCounter)
autorun(() => (dummy = counter.num)) effect(() => (dummy = counter.num))
expect(dummy).toBe(0) expect(dummy).toBe(0)
delete counter.num delete counter.num
@ -102,7 +102,7 @@ describe('observer/autorun', () => {
const counter = observable({ num: 0 }) const counter = observable({ num: 0 })
const parentCounter = observable({ num: 2 }) const parentCounter = observable({ num: 2 })
Object.setPrototypeOf(counter, parentCounter) Object.setPrototypeOf(counter, parentCounter)
autorun(() => (dummy = 'num' in counter)) effect(() => (dummy = 'num' in counter))
expect(dummy).toBe(true) expect(dummy).toBe(true)
delete counter.num delete counter.num
@ -125,8 +125,8 @@ describe('observer/autorun', () => {
} }
}) })
Object.setPrototypeOf(obj, parent) Object.setPrototypeOf(obj, parent)
autorun(() => (dummy = obj.prop)) effect(() => (dummy = obj.prop))
autorun(() => (parentDummy = parent.prop)) effect(() => (parentDummy = parent.prop))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
expect(parentDummy).toBe(undefined) expect(parentDummy).toBe(undefined)
@ -142,7 +142,7 @@ describe('observer/autorun', () => {
it('should observe function call chains', () => { it('should observe function call chains', () => {
let dummy let dummy
const counter = observable({ num: 0 }) const counter = observable({ num: 0 })
autorun(() => (dummy = getNum())) effect(() => (dummy = getNum()))
function getNum() { function getNum() {
return counter.num return counter.num
@ -156,7 +156,7 @@ describe('observer/autorun', () => {
it('should observe iteration', () => { it('should observe iteration', () => {
let dummy let dummy
const list = observable(['Hello']) const list = observable(['Hello'])
autorun(() => (dummy = list.join(' '))) effect(() => (dummy = list.join(' ')))
expect(dummy).toBe('Hello') expect(dummy).toBe('Hello')
list.push('World!') list.push('World!')
@ -168,7 +168,7 @@ describe('observer/autorun', () => {
it('should observe implicit array length changes', () => { it('should observe implicit array length changes', () => {
let dummy let dummy
const list = observable(['Hello']) const list = observable(['Hello'])
autorun(() => (dummy = list.join(' '))) effect(() => (dummy = list.join(' ')))
expect(dummy).toBe('Hello') expect(dummy).toBe('Hello')
list[1] = 'World!' list[1] = 'World!'
@ -181,7 +181,7 @@ describe('observer/autorun', () => {
let dummy let dummy
const list: any[] = observable([]) const list: any[] = observable([])
list[1] = 'World!' list[1] = 'World!'
autorun(() => (dummy = list.join(' '))) effect(() => (dummy = list.join(' ')))
expect(dummy).toBe(' World!') expect(dummy).toBe(' World!')
list[0] = 'Hello' list[0] = 'Hello'
@ -193,7 +193,7 @@ describe('observer/autorun', () => {
it('should observe enumeration', () => { it('should observe enumeration', () => {
let dummy = 0 let dummy = 0
const numbers: any = observable({ num1: 3 }) const numbers: any = observable({ num1: 3 })
autorun(() => { effect(() => {
dummy = 0 dummy = 0
for (let key in numbers) { for (let key in numbers) {
dummy += numbers[key] dummy += numbers[key]
@ -211,8 +211,8 @@ describe('observer/autorun', () => {
const key = Symbol('symbol keyed prop') const key = Symbol('symbol keyed prop')
let dummy, hasDummy let dummy, hasDummy
const obj = observable({ [key]: 'value' }) const obj = observable({ [key]: 'value' })
autorun(() => (dummy = obj[key])) effect(() => (dummy = obj[key]))
autorun(() => (hasDummy = key in obj)) effect(() => (hasDummy = key in obj))
expect(dummy).toBe('value') expect(dummy).toBe('value')
expect(hasDummy).toBe(true) expect(hasDummy).toBe(true)
@ -227,7 +227,7 @@ describe('observer/autorun', () => {
const key = Symbol.isConcatSpreadable const key = Symbol.isConcatSpreadable
let dummy let dummy
const array: any = observable([]) const array: any = observable([])
autorun(() => (dummy = array[key])) effect(() => (dummy = array[key]))
expect(array[key]).toBe(undefined) expect(array[key]).toBe(undefined)
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
@ -242,7 +242,7 @@ describe('observer/autorun', () => {
let dummy let dummy
const obj = observable({ func: oldFunc }) const obj = observable({ func: oldFunc })
autorun(() => (dummy = obj.func)) effect(() => (dummy = obj.func))
expect(dummy).toBe(oldFunc) expect(dummy).toBe(oldFunc)
obj.func = newFunc obj.func = newFunc
@ -255,8 +255,8 @@ describe('observer/autorun', () => {
const getSpy = jest.fn(() => (getDummy = obj.prop)) const getSpy = jest.fn(() => (getDummy = obj.prop))
const hasSpy = jest.fn(() => (hasDummy = 'prop' in obj)) const hasSpy = jest.fn(() => (hasDummy = 'prop' in obj))
autorun(getSpy) effect(getSpy)
autorun(hasSpy) effect(hasSpy)
expect(getDummy).toBe('value') expect(getDummy).toBe('value')
expect(hasDummy).toBe(true) expect(hasDummy).toBe(true)
@ -270,7 +270,7 @@ describe('observer/autorun', () => {
it('should not observe raw mutations', () => { it('should not observe raw mutations', () => {
let dummy let dummy
const obj: any = observable() const obj: any = observable()
autorun(() => (dummy = unwrap(obj).prop)) effect(() => (dummy = unwrap(obj).prop))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
obj.prop = 'value' obj.prop = 'value'
@ -280,7 +280,7 @@ describe('observer/autorun', () => {
it('should not be triggered by raw mutations', () => { it('should not be triggered by raw mutations', () => {
let dummy let dummy
const obj: any = observable() const obj: any = observable()
autorun(() => (dummy = obj.prop)) effect(() => (dummy = obj.prop))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
unwrap(obj).prop = 'value' unwrap(obj).prop = 'value'
@ -299,8 +299,8 @@ describe('observer/autorun', () => {
} }
}) })
Object.setPrototypeOf(obj, parent) Object.setPrototypeOf(obj, parent)
autorun(() => (dummy = obj.prop)) effect(() => (dummy = obj.prop))
autorun(() => (parentDummy = parent.prop)) effect(() => (parentDummy = parent.prop))
expect(dummy).toBe(undefined) expect(dummy).toBe(undefined)
expect(parentDummy).toBe(undefined) expect(parentDummy).toBe(undefined)
@ -313,7 +313,7 @@ describe('observer/autorun', () => {
const counter = observable({ num: 0 }) const counter = observable({ num: 0 })
const counterSpy = jest.fn(() => counter.num++) const counterSpy = jest.fn(() => counter.num++)
autorun(counterSpy) effect(counterSpy)
expect(counter.num).toBe(1) expect(counter.num).toBe(1)
expect(counterSpy).toHaveBeenCalledTimes(1) expect(counterSpy).toHaveBeenCalledTimes(1)
counter.num = 4 counter.num = 4
@ -329,18 +329,18 @@ describe('observer/autorun', () => {
numSpy() numSpy()
} }
}) })
autorun(numSpy) effect(numSpy)
expect(counter.num).toEqual(10) expect(counter.num).toEqual(10)
expect(numSpy).toHaveBeenCalledTimes(10) expect(numSpy).toHaveBeenCalledTimes(10)
}) })
it('should avoid infinite loops with other autoruns', () => { it('should avoid infinite loops with other effects', () => {
const nums = observable({ num1: 0, num2: 1 }) const nums = observable({ num1: 0, num2: 1 })
const spy1 = jest.fn(() => (nums.num1 = nums.num2)) const spy1 = jest.fn(() => (nums.num1 = nums.num2))
const spy2 = jest.fn(() => (nums.num2 = nums.num1)) const spy2 = jest.fn(() => (nums.num2 = nums.num1))
autorun(spy1) effect(spy1)
autorun(spy2) effect(spy2)
expect(nums.num1).toBe(1) expect(nums.num1).toBe(1)
expect(nums.num2).toBe(1) expect(nums.num2).toBe(1)
expect(spy1).toHaveBeenCalledTimes(1) expect(spy1).toHaveBeenCalledTimes(1)
@ -361,12 +361,12 @@ describe('observer/autorun', () => {
function greet() { function greet() {
return 'Hello World' return 'Hello World'
} }
const autorun1 = autorun(greet) const effect1 = effect(greet)
const autorun2 = autorun(greet) const effect2 = effect(greet)
expect(typeof autorun1).toBe('function') expect(typeof effect1).toBe('function')
expect(typeof autorun2).toBe('function') expect(typeof effect2).toBe('function')
expect(autorun1).not.toBe(greet) expect(effect1).not.toBe(greet)
expect(autorun1).not.toBe(autorun2) expect(effect1).not.toBe(effect2)
}) })
it('should discover new branches while running automatically', () => { it('should discover new branches while running automatically', () => {
@ -376,7 +376,7 @@ describe('observer/autorun', () => {
const conditionalSpy = jest.fn(() => { const conditionalSpy = jest.fn(() => {
dummy = obj.run ? obj.prop : 'other' dummy = obj.run ? obj.prop : 'other'
}) })
autorun(conditionalSpy) effect(conditionalSpy)
expect(dummy).toBe('other') expect(dummy).toBe('other')
expect(conditionalSpy).toHaveBeenCalledTimes(1) expect(conditionalSpy).toHaveBeenCalledTimes(1)
@ -395,7 +395,7 @@ describe('observer/autorun', () => {
let dummy let dummy
let run = false let run = false
const obj = observable({ prop: 'value' }) const obj = observable({ prop: 'value' })
const runner = autorun(() => { const runner = effect(() => {
dummy = run ? obj.prop : 'other' dummy = run ? obj.prop : 'other'
}) })
@ -416,7 +416,7 @@ describe('observer/autorun', () => {
const conditionalSpy = jest.fn(() => { const conditionalSpy = jest.fn(() => {
dummy = obj.run ? obj.prop : 'other' dummy = obj.run ? obj.prop : 'other'
}) })
autorun(conditionalSpy) effect(conditionalSpy)
expect(dummy).toBe('value') expect(dummy).toBe('value')
expect(conditionalSpy).toHaveBeenCalledTimes(1) expect(conditionalSpy).toHaveBeenCalledTimes(1)
@ -428,9 +428,9 @@ describe('observer/autorun', () => {
expect(conditionalSpy).toHaveBeenCalledTimes(2) expect(conditionalSpy).toHaveBeenCalledTimes(2)
}) })
it('should not double wrap if the passed function is a autorun', () => { it('should not double wrap if the passed function is a effect', () => {
const runner = autorun(() => {}) const runner = effect(() => {})
const otherRunner = autorun(runner) const otherRunner = effect(runner)
expect(runner).not.toBe(otherRunner) expect(runner).not.toBe(otherRunner)
expect(runner.raw).toBe(otherRunner.raw) expect(runner.raw).toBe(otherRunner.raw)
}) })
@ -444,7 +444,7 @@ describe('observer/autorun', () => {
} }
dummy = obj.prop dummy = obj.prop
}) })
autorun(fnSpy) effect(fnSpy)
expect(fnSpy).toHaveBeenCalledTimes(1) expect(fnSpy).toHaveBeenCalledTimes(1)
obj.prop = 16 obj.prop = 16
@ -452,33 +452,33 @@ describe('observer/autorun', () => {
expect(fnSpy).toHaveBeenCalledTimes(2) expect(fnSpy).toHaveBeenCalledTimes(2)
}) })
it('should allow nested autoruns', () => { it('should allow nested effects', () => {
const nums = observable({ num1: 0, num2: 1, num3: 2 }) const nums = observable({ num1: 0, num2: 1, num3: 2 })
const dummy: any = {} const dummy: any = {}
const childSpy = jest.fn(() => (dummy.num1 = nums.num1)) const childSpy = jest.fn(() => (dummy.num1 = nums.num1))
const childautorun = autorun(childSpy) const childeffect = effect(childSpy)
const parentSpy = jest.fn(() => { const parentSpy = jest.fn(() => {
dummy.num2 = nums.num2 dummy.num2 = nums.num2
childautorun() childeffect()
dummy.num3 = nums.num3 dummy.num3 = nums.num3
}) })
autorun(parentSpy) effect(parentSpy)
expect(dummy).toEqual({ num1: 0, num2: 1, num3: 2 }) expect(dummy).toEqual({ num1: 0, num2: 1, num3: 2 })
expect(parentSpy).toHaveBeenCalledTimes(1) expect(parentSpy).toHaveBeenCalledTimes(1)
expect(childSpy).toHaveBeenCalledTimes(2) expect(childSpy).toHaveBeenCalledTimes(2)
// this should only call the childautorun // this should only call the childeffect
nums.num1 = 4 nums.num1 = 4
expect(dummy).toEqual({ num1: 4, num2: 1, num3: 2 }) expect(dummy).toEqual({ num1: 4, num2: 1, num3: 2 })
expect(parentSpy).toHaveBeenCalledTimes(1) expect(parentSpy).toHaveBeenCalledTimes(1)
expect(childSpy).toHaveBeenCalledTimes(3) expect(childSpy).toHaveBeenCalledTimes(3)
// this calls the parentautorun, which calls the childautorun once // this calls the parenteffect, which calls the childeffect once
nums.num2 = 10 nums.num2 = 10
expect(dummy).toEqual({ num1: 4, num2: 10, num3: 2 }) expect(dummy).toEqual({ num1: 4, num2: 10, num3: 2 })
expect(parentSpy).toHaveBeenCalledTimes(2) expect(parentSpy).toHaveBeenCalledTimes(2)
expect(childSpy).toHaveBeenCalledTimes(4) expect(childSpy).toHaveBeenCalledTimes(4)
// this calls the parentautorun, which calls the childautorun once // this calls the parenteffect, which calls the childeffect once
nums.num3 = 7 nums.num3 = 7
expect(dummy).toEqual({ num1: 4, num2: 10, num3: 7 }) expect(dummy).toEqual({ num1: 4, num2: 10, num3: 7 })
expect(parentSpy).toHaveBeenCalledTimes(3) expect(parentSpy).toHaveBeenCalledTimes(3)
@ -497,7 +497,7 @@ describe('observer/autorun', () => {
} }
const model = observable(new Model()) const model = observable(new Model())
let dummy let dummy
autorun(() => { effect(() => {
dummy = model.count dummy = model.count
}) })
expect(dummy).toBe(0) expect(dummy).toBe(0)
@ -511,7 +511,7 @@ describe('observer/autorun', () => {
runner = _runner runner = _runner
}) })
const obj = observable({ foo: 1 }) const obj = observable({ foo: 1 })
autorun( effect(
() => { () => {
dummy = obj.foo dummy = obj.foo
}, },
@ -537,7 +537,7 @@ describe('observer/autorun', () => {
events.push(e) events.push(e)
}) })
const obj = observable({ foo: 1, bar: 2 }) const obj = observable({ foo: 1, bar: 2 })
const runner = autorun( const runner = effect(
() => { () => {
dummy = obj.foo dummy = obj.foo
dummy = 'bar' in obj dummy = 'bar' in obj
@ -549,19 +549,19 @@ describe('observer/autorun', () => {
expect(onTrack).toHaveBeenCalledTimes(3) expect(onTrack).toHaveBeenCalledTimes(3)
expect(events).toEqual([ expect(events).toEqual([
{ {
runner, effect: runner,
target: unwrap(obj), target: unwrap(obj),
type: OperationTypes.GET, type: OperationTypes.GET,
key: 'foo' key: 'foo'
}, },
{ {
runner, effect: runner,
target: unwrap(obj), target: unwrap(obj),
type: OperationTypes.HAS, type: OperationTypes.HAS,
key: 'bar' key: 'bar'
}, },
{ {
runner, effect: runner,
target: unwrap(obj), target: unwrap(obj),
type: OperationTypes.ITERATE, type: OperationTypes.ITERATE,
key: ITERATE_KEY key: ITERATE_KEY
@ -576,7 +576,7 @@ describe('observer/autorun', () => {
events.push(e) events.push(e)
}) })
const obj = observable({ foo: 1 }) const obj = observable({ foo: 1 })
const runner = autorun( const runner = effect(
() => { () => {
dummy = obj.foo dummy = obj.foo
}, },
@ -587,7 +587,7 @@ describe('observer/autorun', () => {
expect(dummy).toBe(2) expect(dummy).toBe(2)
expect(onTrigger).toHaveBeenCalledTimes(1) expect(onTrigger).toHaveBeenCalledTimes(1)
expect(events[0]).toEqual({ expect(events[0]).toEqual({
runner, effect: runner,
target: unwrap(obj), target: unwrap(obj),
type: OperationTypes.SET, type: OperationTypes.SET,
key: 'foo', key: 'foo',
@ -599,7 +599,7 @@ describe('observer/autorun', () => {
expect(dummy).toBeUndefined() expect(dummy).toBeUndefined()
expect(onTrigger).toHaveBeenCalledTimes(2) expect(onTrigger).toHaveBeenCalledTimes(2)
expect(events[1]).toEqual({ expect(events[1]).toEqual({
runner, effect: runner,
target: unwrap(obj), target: unwrap(obj),
type: OperationTypes.DELETE, type: OperationTypes.DELETE,
key: 'foo', key: 'foo',
@ -610,7 +610,7 @@ describe('observer/autorun', () => {
it('stop', () => { it('stop', () => {
let dummy let dummy
const obj = observable({ prop: 1 }) const obj = observable({ prop: 1 })
const runner = autorun(() => { const runner = effect(() => {
dummy = obj.prop dummy = obj.prop
}) })
obj.prop = 2 obj.prop = 2
@ -619,7 +619,7 @@ describe('observer/autorun', () => {
obj.prop = 3 obj.prop = 3
expect(dummy).toBe(2) expect(dummy).toBe(2)
// stopped runner should still be manually callable // stopped effect should still be manually callable
runner() runner()
expect(dummy).toBe(3) expect(dummy).toBe(3)
}) })
@ -631,7 +631,7 @@ describe('observer/autorun', () => {
}) })
}) })
let dummy let dummy
autorun(() => { effect(() => {
dummy = obj.foo.prop dummy = obj.foo.prop
}) })
expect(dummy).toBe(0) expect(dummy).toBe(0)

View File

@ -8,7 +8,7 @@ import {
markImmutable, markImmutable,
lock, lock,
unlock, unlock,
autorun effect
} from '../src' } from '../src'
describe('observer/immutable', () => { describe('observer/immutable', () => {
@ -75,10 +75,10 @@ describe('observer/immutable', () => {
expect(warn).not.toHaveBeenCalled() expect(warn).not.toHaveBeenCalled()
}) })
it('should not trigger autoruns when locked', () => { it('should not trigger effects when locked', () => {
const observed = immutable({ a: 1 }) const observed = immutable({ a: 1 })
let dummy let dummy
autorun(() => { effect(() => {
dummy = observed.a dummy = observed.a
}) })
expect(dummy).toBe(1) expect(dummy).toBe(1)
@ -87,10 +87,10 @@ describe('observer/immutable', () => {
expect(dummy).toBe(1) expect(dummy).toBe(1)
}) })
it('should trigger autoruns when unlocked', () => { it('should trigger effects when unlocked', () => {
const observed = immutable({ a: 1 }) const observed = immutable({ a: 1 })
let dummy let dummy
autorun(() => { effect(() => {
dummy = observed.a dummy = observed.a
}) })
expect(dummy).toBe(1) expect(dummy).toBe(1)
@ -161,10 +161,10 @@ describe('observer/immutable', () => {
expect(warn).not.toHaveBeenCalled() expect(warn).not.toHaveBeenCalled()
}) })
it('should not trigger autoruns when locked', () => { it('should not trigger effects when locked', () => {
const observed = immutable([{ a: 1 }]) const observed = immutable([{ a: 1 }])
let dummy let dummy
autorun(() => { effect(() => {
dummy = observed[0].a dummy = observed[0].a
}) })
expect(dummy).toBe(1) expect(dummy).toBe(1)
@ -176,10 +176,10 @@ describe('observer/immutable', () => {
expect(dummy).toBe(1) expect(dummy).toBe(1)
}) })
it('should trigger autoruns when unlocked', () => { it('should trigger effects when unlocked', () => {
const observed = immutable([{ a: 1 }]) const observed = immutable([{ a: 1 }])
let dummy let dummy
autorun(() => { effect(() => {
dummy = observed[0].a dummy = observed[0].a
}) })
expect(dummy).toBe(1) expect(dummy).toBe(1)
@ -220,11 +220,11 @@ describe('observer/immutable', () => {
expect(isImmutable(original.get(key1))).toBe(false) expect(isImmutable(original.get(key1))).toBe(false)
}) })
test('should not allow mutation & not trigger autorun', () => { test('should not allow mutation & not trigger effect', () => {
const map = immutable(new Collection()) const map = immutable(new Collection())
const key = {} const key = {}
let dummy let dummy
autorun(() => { effect(() => {
dummy = map.get(key) dummy = map.get(key)
}) })
expect(dummy).toBeUndefined() expect(dummy).toBeUndefined()
@ -234,12 +234,12 @@ describe('observer/immutable', () => {
expect(warn).toHaveBeenCalledTimes(1) expect(warn).toHaveBeenCalledTimes(1)
}) })
test('should allow mutation & trigger autorun when unlocked', () => { test('should allow mutation & trigger effect when unlocked', () => {
const map = immutable(new Collection()) const map = immutable(new Collection())
const isWeak = Collection === WeakMap const isWeak = Collection === WeakMap
const key = {} const key = {}
let dummy let dummy
autorun(() => { effect(() => {
dummy = map.get(key) + (isWeak ? 0 : map.size) dummy = map.get(key) + (isWeak ? 0 : map.size)
}) })
expect(dummy).toBeNaN() expect(dummy).toBeNaN()
@ -289,11 +289,11 @@ describe('observer/immutable', () => {
expect(original.has(observable(key1))).toBe(false) expect(original.has(observable(key1))).toBe(false)
}) })
test('should not allow mutation & not trigger autorun', () => { test('should not allow mutation & not trigger effect', () => {
const set = immutable(new Collection()) const set = immutable(new Collection())
const key = {} const key = {}
let dummy let dummy
autorun(() => { effect(() => {
dummy = set.has(key) dummy = set.has(key)
}) })
expect(dummy).toBe(false) expect(dummy).toBe(false)
@ -303,11 +303,11 @@ describe('observer/immutable', () => {
expect(warn).toHaveBeenCalledTimes(1) expect(warn).toHaveBeenCalledTimes(1)
}) })
test('should allow mutation & trigger autorun when unlocked', () => { test('should allow mutation & trigger effect when unlocked', () => {
const set = immutable(new Collection()) const set = immutable(new Collection())
const key = {} const key = {}
let dummy let dummy
autorun(() => { effect(() => {
dummy = set.has(key) dummy = set.has(key)
}) })
expect(dummy).toBe(false) expect(dummy).toBe(false)

View File

@ -1,180 +0,0 @@
import { OperationTypes } from './operations'
import { Dep, KeyToDepMap, targetMap } from './state'
export interface Autorun {
(): any
isAutorun: true
active: boolean
raw: Function
deps: Array<Dep>
computed?: boolean
scheduler?: Scheduler
onTrack?: Debugger
onTrigger?: Debugger
}
export interface AutorunOptions {
lazy?: boolean
scheduler?: Scheduler
onTrack?: Debugger
onTrigger?: Debugger
}
export type Scheduler = (run: () => any) => void
export type DebuggerEvent = {
runner: Autorun
target: any
type: OperationTypes
key: string | symbol | undefined
}
export type Debugger = (event: DebuggerEvent) => void
export const activeAutorunStack: Autorun[] = []
export const ITERATE_KEY = Symbol('iterate')
export function createAutorun(fn: Function, options: AutorunOptions): Autorun {
const runner = function runner(...args): any {
return run(runner as Autorun, fn, args)
} as Autorun
runner.isAutorun = true
runner.active = true
runner.raw = fn
runner.scheduler = options.scheduler
runner.onTrack = options.onTrack
runner.onTrigger = options.onTrigger
runner.deps = []
return runner
}
function run(runner: Autorun, fn: Function, args: any[]): any {
if (!runner.active) {
return fn(...args)
}
if (activeAutorunStack.indexOf(runner) === -1) {
cleanup(runner)
try {
activeAutorunStack.push(runner)
return fn(...args)
} finally {
activeAutorunStack.pop()
}
}
}
export function cleanup(runner: Autorun) {
for (let i = 0; i < runner.deps.length; i++) {
runner.deps[i].delete(runner)
}
runner.deps = []
}
export function track(
target: any,
type: OperationTypes,
key?: string | symbol
) {
const runner = activeAutorunStack[activeAutorunStack.length - 1]
if (runner) {
if (type === OperationTypes.ITERATE) {
key = ITERATE_KEY
}
// keyMap must exist because only an observed target can call this function
const depsMap = targetMap.get(target) as KeyToDepMap
let dep = depsMap.get(key as string | symbol)
if (!dep) {
depsMap.set(key as string | symbol, (dep = new Set()))
}
if (!dep.has(runner)) {
dep.add(runner)
runner.deps.push(dep)
if (__DEV__ && runner.onTrack) {
runner.onTrack({
runner,
target,
type,
key
})
}
}
}
}
export function trigger(
target: any,
type: OperationTypes,
key?: string | symbol,
extraInfo?: any
) {
const depsMap = targetMap.get(target) as KeyToDepMap
const runners = new Set()
const computedRunners = new Set()
if (type === OperationTypes.CLEAR) {
// collection being cleared, trigger all runners for target
depsMap.forEach(dep => {
addRunners(runners, computedRunners, dep)
})
} else {
// schedule runs for SET | ADD | DELETE
if (key !== void 0) {
addRunners(runners, computedRunners, depsMap.get(key as string | symbol))
}
// also run for iteration key on ADD | DELETE
if (type === OperationTypes.ADD || type === OperationTypes.DELETE) {
const iterationKey = Array.isArray(target) ? 'length' : ITERATE_KEY
addRunners(runners, computedRunners, depsMap.get(iterationKey))
}
}
const run = (runner: Autorun) => {
scheduleRun(runner, target, type, key, extraInfo)
}
// Important: computed runners must be run first so that computed getters
// can be invalidated before any normal runners that depend on them are run.
computedRunners.forEach(run)
runners.forEach(run)
}
function addRunners(
runners: Set<Autorun>,
computedRunners: Set<Autorun>,
runnersToAdd: Set<Autorun> | undefined
) {
if (runnersToAdd !== void 0) {
runnersToAdd.forEach(runner => {
if (runner.computed) {
computedRunners.add(runner)
} else {
runners.add(runner)
}
})
}
}
function scheduleRun(
runner: Autorun,
target: any,
type: OperationTypes,
key: string | symbol | undefined,
extraInfo: any
) {
if (__DEV__ && runner.onTrigger) {
runner.onTrigger(
Object.assign(
{
runner,
target,
key,
type
},
extraInfo
)
)
}
if (runner.scheduler !== void 0) {
runner.scheduler(runner)
} else {
runner()
}
}

View File

@ -1,6 +1,6 @@
import { observable, immutable, unwrap } from './index' import { observable, immutable, unwrap } from './index'
import { OperationTypes } from './operations' import { OperationTypes } from './operations'
import { track, trigger } from './autorun' import { track, trigger } from './effect'
import { LOCKED } from './lock' import { LOCKED } from './lock'
import { isObject } from '@vue/shared' import { isObject } from '@vue/shared'

View File

@ -1,5 +1,5 @@
import { unwrap, observable, immutable } from './index' import { unwrap, observable, immutable } from './index'
import { track, trigger } from './autorun' import { track, trigger } from './effect'
import { OperationTypes } from './operations' import { OperationTypes } from './operations'
import { LOCKED } from './lock' import { LOCKED } from './lock'
import { isObject } from '@vue/shared' import { isObject } from '@vue/shared'

View File

@ -1,9 +1,9 @@
import { autorun } from './index' import { effect } from './index'
import { Autorun, activeAutorunStack } from './autorun' import { ReactiveEffect, activeReactiveEffectStack } from './effect'
export interface ComputedGetter<T = any> { export interface ComputedGetter<T = any> {
(): T (): T
runner: Autorun effect: ReactiveEffect
} }
export function computed<T, C = null>( export function computed<T, C = null>(
@ -12,7 +12,7 @@ export function computed<T, C = null>(
): ComputedGetter<T> { ): 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 = effect(() => getter.call(context, context), {
lazy: true, lazy: true,
scheduler: () => { scheduler: () => {
dirty = true dirty = true
@ -23,21 +23,22 @@ export function computed<T, C = null>(
value = runner() value = runner()
dirty = false dirty = false
} }
// When computed autoruns are accessed in a parent autorun, the parent // When computed effects are accessed in a parent effect, the parent
// should track all the dependencies the computed property has tracked. // should track all the dependencies the computed property has tracked.
// This should also apply for chained computed properties. // This should also apply for chained computed properties.
trackChildRun(runner) trackChildRun(runner)
return value return value
}) as ComputedGetter }) as ComputedGetter
// expose runner so computed can be stopped // expose effect so computed can be stopped
computedGetter.runner = runner computedGetter.effect = runner
// mark runner as computed so that it gets priority during trigger // mark effect as computed so that it gets priority during trigger
runner.computed = true runner.computed = true
return computedGetter return computedGetter
} }
function trackChildRun(childRunner: Autorun) { function trackChildRun(childRunner: ReactiveEffect) {
const parentRunner = activeAutorunStack[activeAutorunStack.length - 1] const parentRunner =
activeReactiveEffectStack[activeReactiveEffectStack.length - 1]
if (parentRunner) { if (parentRunner) {
for (let i = 0; i < childRunner.deps.length; i++) { for (let i = 0; i < childRunner.deps.length; i++) {
const dep = childRunner.deps[i] const dep = childRunner.deps[i]

View File

@ -0,0 +1,183 @@
import { OperationTypes } from './operations'
import { Dep, KeyToDepMap, targetMap } from './state'
export interface ReactiveEffect {
(): any
isEffect: true
active: boolean
raw: Function
deps: Array<Dep>
computed?: boolean
scheduler?: Scheduler
onTrack?: Debugger
onTrigger?: Debugger
}
export interface ReactiveEffectOptions {
lazy?: boolean
scheduler?: Scheduler
onTrack?: Debugger
onTrigger?: Debugger
}
export type Scheduler = (run: () => any) => void
export type DebuggerEvent = {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}
export type Debugger = (event: DebuggerEvent) => void
export const activeReactiveEffectStack: ReactiveEffect[] = []
export const ITERATE_KEY = Symbol('iterate')
export function createReactiveEffect(
fn: Function,
options: ReactiveEffectOptions
): ReactiveEffect {
const effect = function effect(...args): any {
return run(effect as ReactiveEffect, fn, args)
} as ReactiveEffect
effect.isEffect = true
effect.active = true
effect.raw = fn
effect.scheduler = options.scheduler
effect.onTrack = options.onTrack
effect.onTrigger = options.onTrigger
effect.deps = []
return effect
}
function run(effect: ReactiveEffect, fn: Function, args: any[]): any {
if (!effect.active) {
return fn(...args)
}
if (activeReactiveEffectStack.indexOf(effect) === -1) {
cleanup(effect)
try {
activeReactiveEffectStack.push(effect)
return fn(...args)
} finally {
activeReactiveEffectStack.pop()
}
}
}
export function cleanup(effect: ReactiveEffect) {
for (let i = 0; i < effect.deps.length; i++) {
effect.deps[i].delete(effect)
}
effect.deps = []
}
export function track(
target: any,
type: OperationTypes,
key?: string | symbol
) {
const effect = activeReactiveEffectStack[activeReactiveEffectStack.length - 1]
if (effect) {
if (type === OperationTypes.ITERATE) {
key = ITERATE_KEY
}
// keyMap must exist because only an observed target can call this function
const depsMap = targetMap.get(target) as KeyToDepMap
let dep = depsMap.get(key as string | symbol)
if (!dep) {
depsMap.set(key as string | symbol, (dep = new Set()))
}
if (!dep.has(effect)) {
dep.add(effect)
effect.deps.push(dep)
if (__DEV__ && effect.onTrack) {
effect.onTrack({
effect,
target,
type,
key
})
}
}
}
}
export function trigger(
target: any,
type: OperationTypes,
key?: string | symbol,
extraInfo?: any
) {
const depsMap = targetMap.get(target) as KeyToDepMap
const effects = new Set()
const computedRunners = new Set()
if (type === OperationTypes.CLEAR) {
// collection being cleared, trigger all effects for target
depsMap.forEach(dep => {
addRunners(effects, computedRunners, dep)
})
} else {
// schedule runs for SET | ADD | DELETE
if (key !== void 0) {
addRunners(effects, computedRunners, depsMap.get(key as string | symbol))
}
// also run for iteration key on ADD | DELETE
if (type === OperationTypes.ADD || type === OperationTypes.DELETE) {
const iterationKey = Array.isArray(target) ? 'length' : ITERATE_KEY
addRunners(effects, computedRunners, depsMap.get(iterationKey))
}
}
const run = (effect: ReactiveEffect) => {
scheduleRun(effect, target, type, key, extraInfo)
}
// Important: computed effects must be run first so that computed getters
// can be invalidated before any normal effects that depend on them are run.
computedRunners.forEach(run)
effects.forEach(run)
}
function addRunners(
effects: Set<ReactiveEffect>,
computedRunners: Set<ReactiveEffect>,
effectsToAdd: Set<ReactiveEffect> | undefined
) {
if (effectsToAdd !== void 0) {
effectsToAdd.forEach(effect => {
if (effect.computed) {
computedRunners.add(effect)
} else {
effects.add(effect)
}
})
}
}
function scheduleRun(
effect: ReactiveEffect,
target: any,
type: OperationTypes,
key: string | symbol | undefined,
extraInfo: any
) {
if (__DEV__ && effect.onTrigger) {
effect.onTrigger(
Object.assign(
{
effect,
target,
key,
type
},
extraInfo
)
)
}
if (effect.scheduler !== void 0) {
effect.scheduler(effect)
} else {
effect()
}
}

View File

@ -17,14 +17,14 @@ import {
} from './state' } from './state'
import { import {
createAutorun, createReactiveEffect,
cleanup, cleanup,
Autorun, ReactiveEffect,
AutorunOptions, ReactiveEffectOptions,
DebuggerEvent DebuggerEvent
} from './autorun' } from './effect'
export { Autorun, AutorunOptions, DebuggerEvent } export { ReactiveEffect, ReactiveEffectOptions, DebuggerEvent }
export { OperationTypes } from './operations' export { OperationTypes } from './operations'
export { computed, ComputedGetter } from './computed' export { computed, ComputedGetter } from './computed'
export { lock, unlock } from './lock' export { lock, unlock } from './lock'
@ -114,24 +114,24 @@ function createObservable(
return observed return observed
} }
export function autorun( export function effect(
fn: Function, fn: Function,
options: AutorunOptions = EMPTY_OBJ options: ReactiveEffectOptions = EMPTY_OBJ
): Autorun { ): ReactiveEffect {
if ((fn as Autorun).isAutorun) { if ((fn as ReactiveEffect).isEffect) {
fn = (fn as Autorun).raw fn = (fn as ReactiveEffect).raw
} }
const runner = createAutorun(fn, options) const effect = createReactiveEffect(fn, options)
if (!options.lazy) { if (!options.lazy) {
runner() effect()
} }
return runner return effect
} }
export function stop(runner: Autorun) { export function stop(effect: ReactiveEffect) {
if (runner.active) { if (effect.active) {
cleanup(runner) cleanup(effect)
runner.active = false effect.active = false
} }
} }

View File

@ -1,10 +1,10 @@
import { Autorun } from './autorun' import { ReactiveEffect } from './effect'
// The main WeakMap that stores {target -> key -> dep} connections. // The main WeakMap that stores {target -> key -> dep} connections.
// Conceptually, it's easier to think of a dependency as a Dep class // Conceptually, it's easier to think of a dependency as a Dep class
// which maintains a Set of subscribers, but we simply store them as // which maintains a Set of subscribers, but we simply store them as
// raw Sets to reduce memory overhead. // raw Sets to reduce memory overhead.
export type Dep = Set<Autorun> export type Dep = Set<ReactiveEffect>
export type KeyToDepMap = Map<string | symbol, Dep> export type KeyToDepMap = Map<string | symbol, Dep>
export const targetMap: WeakMap<any, KeyToDepMap> = new WeakMap() export const targetMap: WeakMap<any, KeyToDepMap> = new WeakMap()

View File

@ -12,7 +12,9 @@ import {
nextTick, nextTick,
resetOps, resetOps,
dumpOps, dumpOps,
NodeOpTypes NodeOpTypes,
createFragment,
createTextVNode
} from '@vue/runtime-test' } from '@vue/runtime-test'
describe('Fragments', () => { describe('Fragments', () => {
@ -57,9 +59,12 @@ describe('Fragments', () => {
class App extends Component { class App extends Component {
render() { render() {
return state.ok return state.ok
? h.f([h('div', 'one'), h.t('two')], ChildrenFlags.NONE_KEYED_VNODES) ? createFragment(
: h.f( [h('div', 'one'), createTextVNode('two')],
[h('div', 'foo'), h.t('bar'), h.t('baz')], ChildrenFlags.NONE_KEYED_VNODES
)
: createFragment(
[h('div', 'foo'), createTextVNode('bar'), createTextVNode('baz')],
ChildrenFlags.NONE_KEYED_VNODES ChildrenFlags.NONE_KEYED_VNODES
) )
} }

View File

@ -8,7 +8,7 @@ import {
WatchOptions WatchOptions
} from './componentOptions' } from './componentOptions'
import { setupWatcher } from './componentWatch' import { setupWatcher } from './componentWatch'
import { Autorun, DebuggerEvent, ComputedGetter } from '@vue/observer' import { ReactiveEffect, DebuggerEvent, ComputedGetter } from '@vue/observer'
import { nextTick } from '@vue/scheduler' import { nextTick } from '@vue/scheduler'
import { ErrorTypes } from './errorHandling' import { ErrorTypes } from './errorHandling'
import { initializeComponentInstance } from './componentUtils' import { initializeComponentInstance } from './componentUtils'
@ -101,7 +101,7 @@ export interface ComponentInstance<P = {}, D = {}>
$children: ComponentInstance[] $children: ComponentInstance[]
$options: ComponentOptions<P, D> $options: ComponentOptions<P, D>
_updateHandle: Autorun _update: ReactiveEffect
_queueJob: ((fn: () => void) => void) _queueJob: ((fn: () => void) => void)
_self: ComponentInstance<P, D> // on proxies only _self: ComponentInstance<P, D> // on proxies only
} }
@ -128,11 +128,11 @@ class InternalComponent implements PublicInstanceMethods {
_rawData: Data | null = null _rawData: Data | null = null
_computedGetters: Record<string, ComputedGetter> | null = null _computedGetters: Record<string, ComputedGetter> | null = null
_watchHandles: Set<Autorun> | null = null _watchHandles: Set<ReactiveEffect> | null = null
_mounted: boolean = false _mounted: boolean = false
_unmounted: boolean = false _unmounted: boolean = false
_events: { [event: string]: Function[] | null } | null = null _events: { [event: string]: Function[] | null } | null = null
_updateHandle: Autorun | null = null _update: ReactiveEffect | null = null
_queueJob: ((fn: () => void) => void) | null = null _queueJob: ((fn: () => void) => void) | null = null
_isVue: boolean = true _isVue: boolean = true
_inactiveRoot: boolean = false _inactiveRoot: boolean = false

View File

@ -25,7 +25,7 @@ export function teardownComputed(instance: ComponentInstance) {
const handles = instance._computedGetters const handles = instance._computedGetters
if (handles !== null) { if (handles !== null) {
for (const key in handles) { for (const key in handles) {
stop(handles[key].runner) stop(handles[key].effect)
} }
} }
} }

View File

@ -158,7 +158,7 @@ export function teardownComponentInstance(instance: ComponentInstance) {
1 1
) )
} }
stop(instance._updateHandle) stop(instance._update)
teardownComputed(instance) teardownComputed(instance)
teardownWatch(instance) teardownWatch(instance)
} }

View File

@ -8,7 +8,7 @@ import {
} from '@vue/shared' } from '@vue/shared'
import { ComponentInstance } from './component' import { ComponentInstance } from './component'
import { ComponentWatchOptions, WatchOptions } from './componentOptions' import { ComponentWatchOptions, WatchOptions } from './componentOptions'
import { autorun, stop } from '@vue/observer' import { effect, stop } from '@vue/observer'
import { queueJob } from '@vue/scheduler' import { queueJob } from '@vue/scheduler'
import { handleError, ErrorTypes } from './errorHandling' import { handleError, ErrorTypes } from './errorHandling'
import { warn } from './warning' import { warn } from './warning'
@ -70,7 +70,7 @@ export function setupWatcher(
} }
} }
const runner = autorun(getter, { const runner = effect(getter, {
lazy: true, lazy: true,
scheduler: options.sync scheduler: options.sync
? applyCb ? applyCb

View File

@ -1,15 +1,15 @@
import { import {
autorun, effect as createReactiveEffect,
stop, stop as stopReactiveEffect,
Autorun, ReactiveEffect,
immutable, immutable,
AutorunOptions ReactiveEffectOptions
} from '@vue/observer' } from '@vue/observer'
import { import {
queueJob, queueJob,
handleSchedulerError, handleSchedulerError,
nextTick, nextTick,
queueEffect, queuePostEffect,
flushEffects, flushEffects,
queueNodeOp queueNodeOp
} from '@vue/scheduler' } from '@vue/scheduler'
@ -78,7 +78,7 @@ export interface RendererOptions {
export interface FunctionalHandle { export interface FunctionalHandle {
prev: VNode prev: VNode
next: VNode next: VNode
update: Autorun update: ReactiveEffect
container: RenderNode | null container: RenderNode | null
} }
@ -206,12 +206,12 @@ export function createRenderer(options: RendererOptions) {
queueInsertOrAppend(container, el, endNode) queueInsertOrAppend(container, el, endNode)
} }
if (ref) { if (ref) {
queueEffect(() => { queuePostEffect(() => {
ref(el) ref(el)
}) })
} }
if (data != null && data.vnodeMounted) { if (data != null && data.vnodeMounted) {
queueEffect(() => { queuePostEffect(() => {
data.vnodeMounted(vnode) data.vnodeMounted(vnode)
}) })
} }
@ -272,7 +272,7 @@ export function createRenderer(options: RendererOptions) {
}) })
const doMount = () => { const doMount = () => {
handle.update = autorun( handle.update = createReactiveEffect(
() => { () => {
if (!handle.next) { if (!handle.next) {
// initial mount // initial mount
@ -280,7 +280,7 @@ export function createRenderer(options: RendererOptions) {
pushWarningContext(vnode) pushWarningContext(vnode)
} }
const subTree = (vnode.children = renderFunctionalRoot(vnode)) const subTree = (vnode.children = renderFunctionalRoot(vnode))
queueEffect(() => { queuePostEffect(() => {
vnode.el = subTree.el as RenderNode vnode.el = subTree.el as RenderNode
}) })
mount(subTree, container, vnode as MountedVNode, isSVG, endNode) mount(subTree, container, vnode as MountedVNode, isSVG, endNode)
@ -306,7 +306,7 @@ export function createRenderer(options: RendererOptions) {
doMount() doMount()
// cleanup if mount is invalidated before committed // cleanup if mount is invalidated before committed
return () => { return () => {
stop(handle.update) stopReactiveEffect(handle.update)
} }
}) })
} }
@ -319,7 +319,7 @@ export function createRenderer(options: RendererOptions) {
} }
const prevTree = prev.children as MountedVNode const prevTree = prev.children as MountedVNode
const nextTree = (next.children = renderFunctionalRoot(next)) const nextTree = (next.children = renderFunctionalRoot(next))
queueEffect(() => { queuePostEffect(() => {
next.el = nextTree.el next.el = nextTree.el
}) })
patch( patch(
@ -355,7 +355,7 @@ export function createRenderer(options: RendererOptions) {
const { children, childFlags } = vnode const { children, childFlags } = vnode
switch (childFlags) { switch (childFlags) {
case ChildrenFlags.SINGLE_VNODE: case ChildrenFlags.SINGLE_VNODE:
queueEffect(() => { queuePostEffect(() => {
vnode.el = (children as MountedVNode).el vnode.el = (children as MountedVNode).el
}) })
mount(children as VNode, container, contextVNode, isSVG, endNode) mount(children as VNode, container, contextVNode, isSVG, endNode)
@ -366,7 +366,7 @@ export function createRenderer(options: RendererOptions) {
vnode.el = placeholder.el vnode.el = placeholder.el
break break
default: default:
queueEffect(() => { queuePostEffect(() => {
vnode.el = (children as MountedVNode[])[0].el vnode.el = (children as MountedVNode[])[0].el
}) })
mountArrayChildren( mountArrayChildren(
@ -403,7 +403,7 @@ export function createRenderer(options: RendererOptions) {
) )
} }
if (ref) { if (ref) {
queueEffect(() => { queuePostEffect(() => {
ref(target) ref(target)
}) })
} }
@ -638,7 +638,7 @@ export function createRenderer(options: RendererOptions) {
// then retrieve its next sibling to use as the end node for patchChildren. // then retrieve its next sibling to use as the end node for patchChildren.
const endNode = platformNextSibling(getVNodeLastEl(prevVNode)) const endNode = platformNextSibling(getVNodeLastEl(prevVNode))
const { childFlags, children } = nextVNode const { childFlags, children } = nextVNode
queueEffect(() => { queuePostEffect(() => {
switch (childFlags) { switch (childFlags) {
case ChildrenFlags.SINGLE_VNODE: case ChildrenFlags.SINGLE_VNODE:
nextVNode.el = (children as MountedVNode).el nextVNode.el = (children as MountedVNode).el
@ -1181,7 +1181,7 @@ export function createRenderer(options: RendererOptions) {
} }
} else { } else {
// functional // functional
stop((handle as FunctionalHandle).update) stopReactiveEffect((handle as FunctionalHandle).update)
unmount(children as MountedVNode) unmount(children as MountedVNode)
} }
} else if (flags & VNodeFlags.PORTAL) { } else if (flags & VNodeFlags.PORTAL) {
@ -1293,16 +1293,16 @@ export function createRenderer(options: RendererOptions) {
} = instance } = instance
instance.$forceUpdate = () => { instance.$forceUpdate = () => {
queueJob(instance._updateHandle) queueJob(instance._update)
} }
const autorunOptions: AutorunOptions = { const effectOptions: ReactiveEffectOptions = {
scheduler: queueJob scheduler: queueJob
} }
if (__DEV__) { if (__DEV__) {
if (renderTracked) { if (renderTracked) {
autorunOptions.onTrack = event => { effectOptions.onTrack = event => {
callLifecycleHookWithHandler( callLifecycleHookWithHandler(
renderTracked, renderTracked,
$proxy, $proxy,
@ -1312,7 +1312,7 @@ export function createRenderer(options: RendererOptions) {
} }
} }
if (renderTriggered) { if (renderTriggered) {
autorunOptions.onTrigger = event => { effectOptions.onTrigger = event => {
callLifecycleHookWithHandler( callLifecycleHookWithHandler(
renderTriggered, renderTriggered,
$proxy, $proxy,
@ -1323,7 +1323,7 @@ export function createRenderer(options: RendererOptions) {
} }
} }
instance._updateHandle = autorun(() => { instance._update = createReactiveEffect(() => {
if (instance._unmounted) { if (instance._unmounted) {
return return
} }
@ -1340,7 +1340,7 @@ export function createRenderer(options: RendererOptions) {
instance.$vnode = renderInstanceRoot(instance) as MountedVNode instance.$vnode = renderInstanceRoot(instance) as MountedVNode
queueEffect(() => { queuePostEffect(() => {
vnode.el = instance.$vnode.el vnode.el = instance.$vnode.el
if (__COMPAT__) { if (__COMPAT__) {
// expose __vue__ for devtools // expose __vue__ for devtools
@ -1360,7 +1360,7 @@ export function createRenderer(options: RendererOptions) {
mount(instance.$vnode, container, vnode as MountedVNode, isSVG, endNode) mount(instance.$vnode, container, vnode as MountedVNode, isSVG, endNode)
} }
}, autorunOptions) }, effectOptions)
if (__DEV__) { if (__DEV__) {
popWarningContext() popWarningContext()
@ -1397,7 +1397,7 @@ export function createRenderer(options: RendererOptions) {
const nextVNode = renderInstanceRoot(instance) as MountedVNode const nextVNode = renderInstanceRoot(instance) as MountedVNode
queueEffect(() => { queuePostEffect(() => {
instance.$vnode = nextVNode instance.$vnode = nextVNode
const el = nextVNode.el as RenderNode const el = nextVNode.el as RenderNode
if (__COMPAT__) { if (__COMPAT__) {
@ -1486,7 +1486,7 @@ export function createRenderer(options: RendererOptions) {
if (__DEV__) { if (__DEV__) {
popWarningContext() popWarningContext()
} }
queueEffect(() => { queuePostEffect(() => {
callActivatedHook(instance, true) callActivatedHook(instance, true)
}) })
} }

View File

@ -1,4 +1,4 @@
import { queueJob, queueEffect, nextTick } from '../src/index' import { queueJob, queuePostEffect, nextTick } from '../src/index'
describe('scheduler', () => { describe('scheduler', () => {
it('queueJob', async () => { it('queueJob', async () => {
@ -36,11 +36,11 @@ describe('scheduler', () => {
const calls: any = [] const calls: any = []
const job1 = () => { const job1 = () => {
calls.push('job1') calls.push('job1')
queueEffect(cb1) queuePostEffect(cb1)
} }
const job2 = () => { const job2 = () => {
calls.push('job2') calls.push('job2')
queueEffect(cb2) queuePostEffect(cb2)
} }
const cb1 = () => { const cb1 = () => {
calls.push('cb1') calls.push('cb1')
@ -59,13 +59,13 @@ describe('scheduler', () => {
const calls: any = [] const calls: any = []
const job1 = () => { const job1 = () => {
calls.push('job1') calls.push('job1')
queueEffect(cb1) queuePostEffect(cb1)
// job1 queues job2 // job1 queues job2
queueJob(job2) queueJob(job2)
} }
const job2 = () => { const job2 = () => {
calls.push('job2') calls.push('job2')
queueEffect(cb2) queuePostEffect(cb2)
} }
const cb1 = () => { const cb1 = () => {
calls.push('cb1') calls.push('cb1')
@ -96,11 +96,11 @@ describe('scheduler', () => {
expect(calls).toEqual(['job1', 'job2']) expect(calls).toEqual(['job1', 'job2'])
}) })
it('queueJob inside postCommitCb', async () => { it('queueJob inside postEffect', async () => {
const calls: any = [] const calls: any = []
const job1 = () => { const job1 = () => {
calls.push('job1') calls.push('job1')
queueEffect(cb1) queuePostEffect(cb1)
} }
const cb1 = () => { const cb1 = () => {
// queue another job in postFlushCb // queue another job in postFlushCb
@ -109,7 +109,7 @@ describe('scheduler', () => {
} }
const job2 = () => { const job2 = () => {
calls.push('job2') calls.push('job2')
queueEffect(cb2) queuePostEffect(cb2)
} }
const cb2 = () => { const cb2 = () => {
calls.push('cb2') calls.push('cb2')

View File

@ -31,15 +31,15 @@ interface Job<T extends Function = () => void> {
ops: Op[] ops: Op[]
// Any post DOM mutation side-effects (updated / mounted hooks, refs) are // Any post DOM mutation side-effects (updated / mounted hooks, refs) are
// buffered inside the job's effects queue. // buffered inside the job's effects queue.
// Effects are queued by calling `queueEffect` inside the job function. // Effects are queued by calling `queuePostEffect` inside the job function.
effects: Function[] postEffects: Function[]
// A job may queue other jobs (e.g. a parent component update triggers the // A job may queue other jobs (e.g. a parent component update triggers the
// update of a child component). Jobs queued by another job is kept in the // update of a child component). Jobs queued by another job is kept in the
// parent's children array, so that in case the parent job is invalidated, // parent's children array, so that in case the parent job is invalidated,
// all its children can be invalidated as well (recursively). // all its children can be invalidated as well (recursively).
children: Job[] children: Job[]
// Sometimes it's inevitable for a stage fn to produce some side effects // Sometimes it's inevitable for a stage fn to produce some side effects
// (e.g. a component instance sets up an Autorun). In those cases the stage fn // (e.g. a component instance sets up an ReactiveEffect). In those cases the stage fn
// can return a cleanup function which will be called when the job is // can return a cleanup function which will be called when the job is
// invalidated. // invalidated.
cleanup: T | null cleanup: T | null
@ -172,8 +172,8 @@ function flushAfterMacroTask() {
// This is the main API of the scheduler. The raw job can actually be any // This is the main API of the scheduler. The raw job can actually be any
// function, but since they are invalidated by identity, it is important that // function, but since they are invalidated by identity, it is important that
// a component's update job is a consistent function across its lifecycle - // a component's update job is a consistent function across its lifecycle -
// in the renderer, it's actually instance._updateHandle which is in turn // in the renderer, it's actually instance._update which is in turn
// an Autorun function. // an ReactiveEffect function.
export function queueJob(rawJob: Function) { export function queueJob(rawJob: Function) {
const job = rawJob as Job const job = rawJob as Job
if (currentJob) { if (currentJob) {
@ -196,9 +196,9 @@ export function queueJob(rawJob: Function) {
} }
} }
export function queueEffect(fn: Function) { export function queuePostEffect(fn: Function) {
if (currentJob) { if (currentJob) {
currentJob.effects.push(fn) currentJob.postEffects.push(fn)
} else { } else {
postEffectsQueue.push(fn) postEffectsQueue.push(fn)
} }
@ -296,13 +296,13 @@ function flush(): void {
function resetJob(job: Job) { function resetJob(job: Job) {
job.ops.length = 0 job.ops.length = 0
job.effects.length = 0 job.postEffects.length = 0
job.children.length = 0 job.children.length = 0
} }
function queueJobForStaging(job: Job) { function queueJobForStaging(job: Job) {
job.ops = job.ops || [] job.ops = job.ops || []
job.effects = job.effects || [] job.postEffects = job.postEffects || []
job.children = job.children || [] job.children = job.children || []
resetJob(job) resetJob(job)
// inherit parent job's expiration deadline // inherit parent job's expiration deadline
@ -361,13 +361,13 @@ function stageJob(job: Job) {
} }
function commitJob(job: Job) { function commitJob(job: Job) {
const { ops, effects } = job const { ops, postEffects } = job
for (let i = 0; i < ops.length; i++) { for (let i = 0; i < ops.length; i++) {
applyOp(ops[i]) applyOp(ops[i])
} }
// queue post commit cbs // queue post commit cbs
if (effects) { if (postEffects) {
postEffectsQueue.push(...effects) postEffectsQueue.push(...postEffects)
} }
resetJob(job) resetJob(job)
job.status = JobStatus.IDLE job.status = JobStatus.IDLE