Skip to content

Commit

Permalink
chore(reactive): improve strict mode update strategy (#3233)
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang authored Jun 27, 2022
1 parent fac7b67 commit 5c12281
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 29 deletions.
20 changes: 11 additions & 9 deletions packages/reactive-react/src/hooks/useObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ export const useObserver = <T extends () => any>(
options?: IObserverOptions
): ReturnType<T> => {
const forceUpdate = useForceUpdate()
const unMountRef = React.useRef(false)
const mountedRef = React.useRef(false)
const trackerRef = React.useRef<Tracker>(null)
const gcRef = React.useRef<GarbageCollector>()
const [objectRetainedByReact] = React.useState(
objectToBeRetainedByReactFactory
)
if (!trackerRef.current) {
trackerRef.current = new Tracker(() => {
if (!mountedRef.current) return
if (typeof options?.scheduler === 'function') {
options.scheduler(forceUpdate)
} else {
Expand All @@ -42,16 +43,17 @@ export const useObserver = <T extends () => any>(
}

React.useEffect(() => {
unMountRef.current = false
mountedRef.current = true
gcRef.current.close()
const dispose = () => {
if (trackerRef.current && !mountedRef.current) {
trackerRef.current.dispose()
trackerRef.current = null
}
}
return () => {
unMountRef.current = true
immediate(() => {
if (trackerRef.current && unMountRef.current) {
trackerRef.current.dispose()
trackerRef.current = null
}
})
mountedRef.current = false
immediate(dispose)
}
}, [])

Expand Down
2 changes: 1 addition & 1 deletion packages/reactive/src/__tests__/array.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ test('ArraySet', () => {
const handler1 = jest.fn()
set.add(11)
set.add(22)
set.forEachDelete(handler1)
set.batchDelete(handler1)
expect(handler1).toBeCalledTimes(2)
expect(handler1).nthCalledWith(1, 11)
expect(handler1).nthCalledWith(2, 22)
Expand Down
2 changes: 1 addition & 1 deletion packages/reactive/src/__tests__/tracker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,5 @@ test('shared scheduler with multi tracker(mock react strict mode)', () => {
obs.value = 123

expect(scheduler1).toBeCalledTimes(1)
expect(scheduler2).toBeCalledTimes(1)
expect(scheduler2).toBeCalledTimes(0)
})
33 changes: 18 additions & 15 deletions packages/reactive/src/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const toArray = (value: any) => {

export class ArraySet<T> {
value: T[]
batchDeleting = false
forEachIndex = 0
constructor(value: T[] = []) {
this.value = value
}
Expand All @@ -24,30 +24,33 @@ export class ArraySet<T> {
}

delete(item: T) {
if (this.batchDeleting) return //批量删除时禁止单独删除,会影响计数执行器
const index = this.value.indexOf(item)
if (index > -1) {
this.value.splice(index, 1)
const eachIndex = this.forEachIndex
const findIndex = this.value.indexOf(item)
if (findIndex > -1) {
this.value.splice(findIndex, 1)
if (findIndex <= eachIndex) {
this.forEachIndex -= 1
}
}
}

forEach(callback: (value: T) => void) {
if (this.value.length === 0) return
for (let index = 0; index < this.value.length; index++) {
callback(this.value[index])
this.forEachIndex = 0
for (; this.forEachIndex < this.value.length; this.forEachIndex++) {
callback(this.value[this.forEachIndex])
}
}

forEachDelete(callback: (value: T) => void) {
batchDelete(callback: (value: T) => void) {
if (this.value.length === 0) return
this.batchDeleting = true
for (let index = 0; index < this.value.length; index++) {
const item = this.value[index]
this.value.splice(index, 1)
callback(item)
index--
this.forEachIndex = 0
for (; this.forEachIndex < this.value.length; this.forEachIndex++) {
const value = this.value[this.forEachIndex]
this.value.splice(this.forEachIndex, 1)
this.forEachIndex--
callback(value)
}
this.batchDeleting = false
}

clear() {
Expand Down
6 changes: 3 additions & 3 deletions packages/reactive/src/reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const batchScopeEnd = () => {
const prevUntrackCount = UntrackCount.value
BatchScope.value = false
UntrackCount.value = 0
PendingScopeReactions.forEachDelete((reaction) => {
PendingScopeReactions.batchDelete((reaction) => {
if (isFn(reaction._scheduler)) {
reaction._scheduler(reaction)
} else {
Expand All @@ -223,7 +223,7 @@ export const isScopeBatching = () => BatchScope.value
export const isUntracking = () => UntrackCount.value > 0

export const executePendingReactions = () => {
PendingReactions.forEachDelete((reaction) => {
PendingReactions.batchDelete((reaction) => {
if (isFn(reaction._scheduler)) {
reaction._scheduler(reaction)
} else {
Expand All @@ -233,7 +233,7 @@ export const executePendingReactions = () => {
}

export const executeBatchEndpoints = () => {
BatchEndpoints.forEachDelete((callback) => {
BatchEndpoints.batchDelete((callback) => {
callback()
})
}
Expand Down

0 comments on commit 5c12281

Please sign in to comment.