1
1
import {
2
- ref ,
3
2
reactive ,
4
3
effect ,
5
4
stop ,
@@ -12,7 +11,8 @@ import {
12
11
readonly ,
13
12
ReactiveEffectRunner
14
13
} from '../src/index'
15
- import { ITERATE_KEY } from '../src/effect'
14
+ import { pauseScheduling , resetScheduling } from '../src/effect'
15
+ import { ITERATE_KEY , getDepFromReactive } from '../src/reactiveEffect'
16
16
17
17
describe ( 'reactivity/effect' , ( ) => {
18
18
it ( 'should run the passed function once (wrapped by a effect)' , ( ) => {
@@ -574,8 +574,8 @@ describe('reactivity/effect', () => {
574
574
expect ( output . fx2 ) . toBe ( 1 + 3 + 3 )
575
575
expect ( fx1Spy ) . toHaveBeenCalledTimes ( 1 )
576
576
577
- // Invoked twice due to change of fx1.
578
- expect ( fx2Spy ) . toHaveBeenCalledTimes ( 2 )
577
+ // Invoked due to change of fx1.
578
+ expect ( fx2Spy ) . toHaveBeenCalledTimes ( 1 )
579
579
580
580
fx1Spy . mockClear ( )
581
581
fx2Spy . mockClear ( )
@@ -821,26 +821,6 @@ describe('reactivity/effect', () => {
821
821
expect ( dummy ) . toBe ( 3 )
822
822
} )
823
823
824
- // #5707
825
- // when an effect completes its run, it should clear the tracking bits of
826
- // its tracked deps. However, if the effect stops itself, the deps list is
827
- // emptied so their bits are never cleared.
828
- it ( 'edge case: self-stopping effect tracking ref' , ( ) => {
829
- const c = ref ( true )
830
- const runner = effect ( ( ) => {
831
- // reference ref
832
- if ( ! c . value ) {
833
- // stop itself while running
834
- stop ( runner )
835
- }
836
- } )
837
- // trigger run
838
- c . value = ! c . value
839
- // should clear bits
840
- expect ( ( c as any ) . dep . w ) . toBe ( 0 )
841
- expect ( ( c as any ) . dep . n ) . toBe ( 0 )
842
- } )
843
-
844
824
it ( 'events: onStop' , ( ) => {
845
825
const onStop = vi . fn ( )
846
826
const runner = effect ( ( ) => { } , {
@@ -1015,4 +995,83 @@ describe('reactivity/effect', () => {
1015
995
expect ( has ) . toBe ( false )
1016
996
} )
1017
997
} )
998
+
999
+ it ( 'should be triggered once with pauseScheduling' , ( ) => {
1000
+ const counter = reactive ( { num : 0 } )
1001
+
1002
+ const counterSpy = vi . fn ( ( ) => counter . num )
1003
+ effect ( counterSpy )
1004
+
1005
+ counterSpy . mockClear ( )
1006
+
1007
+ pauseScheduling ( )
1008
+ counter . num ++
1009
+ counter . num ++
1010
+ resetScheduling ( )
1011
+ expect ( counterSpy ) . toHaveBeenCalledTimes ( 1 )
1012
+ } )
1013
+
1014
+ describe ( 'empty dep cleanup' , ( ) => {
1015
+ it ( 'should remove the dep when the effect is stopped' , ( ) => {
1016
+ const obj = reactive ( { prop : 1 } )
1017
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1018
+ const runner = effect ( ( ) => obj . prop )
1019
+ const dep = getDepFromReactive ( toRaw ( obj ) , 'prop' )
1020
+ expect ( dep ) . toHaveLength ( 1 )
1021
+ obj . prop = 2
1022
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBe ( dep )
1023
+ expect ( dep ) . toHaveLength ( 1 )
1024
+ stop ( runner )
1025
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1026
+ obj . prop = 3
1027
+ runner ( )
1028
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1029
+ } )
1030
+
1031
+ it ( 'should only remove the dep when the last effect is stopped' , ( ) => {
1032
+ const obj = reactive ( { prop : 1 } )
1033
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1034
+ const runner1 = effect ( ( ) => obj . prop )
1035
+ const dep = getDepFromReactive ( toRaw ( obj ) , 'prop' )
1036
+ expect ( dep ) . toHaveLength ( 1 )
1037
+ const runner2 = effect ( ( ) => obj . prop )
1038
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBe ( dep )
1039
+ expect ( dep ) . toHaveLength ( 2 )
1040
+ obj . prop = 2
1041
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBe ( dep )
1042
+ expect ( dep ) . toHaveLength ( 2 )
1043
+ stop ( runner1 )
1044
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBe ( dep )
1045
+ expect ( dep ) . toHaveLength ( 1 )
1046
+ obj . prop = 3
1047
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBe ( dep )
1048
+ expect ( dep ) . toHaveLength ( 1 )
1049
+ stop ( runner2 )
1050
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1051
+ obj . prop = 4
1052
+ runner1 ( )
1053
+ runner2 ( )
1054
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1055
+ } )
1056
+
1057
+ it ( 'should remove the dep when it is no longer used by the effect' , ( ) => {
1058
+ const obj = reactive < { a : number ; b : number ; c : 'a' | 'b' } > ( {
1059
+ a : 1 ,
1060
+ b : 2 ,
1061
+ c : 'a'
1062
+ } )
1063
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'prop' ) ) . toBeUndefined ( )
1064
+ effect ( ( ) => obj [ obj . c ] )
1065
+ const depC = getDepFromReactive ( toRaw ( obj ) , 'c' )
1066
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'a' ) ) . toHaveLength ( 1 )
1067
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'b' ) ) . toBeUndefined ( )
1068
+ expect ( depC ) . toHaveLength ( 1 )
1069
+ obj . c = 'b'
1070
+ obj . a = 4
1071
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'a' ) ) . toBeUndefined ( )
1072
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'b' ) ) . toHaveLength ( 1 )
1073
+ expect ( getDepFromReactive ( toRaw ( obj ) , 'c' ) ) . toBe ( depC )
1074
+ expect ( depC ) . toHaveLength ( 1 )
1075
+ } )
1076
+ } )
1018
1077
} )
0 commit comments