Skip to content

Commit c291dbd

Browse files
fix(proxy-state-tree): invalidate proxies when path has changed
1 parent fcc6d8d commit c291dbd

File tree

3 files changed

+89
-7
lines changed

3 files changed

+89
-7
lines changed

packages/node_modules/proxy-state-tree/src/index.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,69 @@ describe('ARRAYS', () => {
159159
tree.clearPathsTracking(trackIdA)
160160
}).toThrow()
161161
})
162+
test('should correctly keep track of changing indexes', () => {
163+
expect.assertions(3)
164+
let listener
165+
let iterations = 0
166+
const tree = new ProxyStateTree({
167+
items: [],
168+
})
169+
const state = tree.get()
170+
171+
function trackPaths() {
172+
const trackId = tree.startPathsTracking()
173+
state.items.map((item) => item.title)
174+
const paths = tree.clearPathsTracking(trackId)
175+
176+
if (iterations === 1) {
177+
expect(Array.from(paths)).toEqual([
178+
'items',
179+
'items.0',
180+
'items.0.title',
181+
])
182+
} else if (iterations === 2) {
183+
expect(Array.from(paths)).toEqual([
184+
'items',
185+
'items.0',
186+
'items.0.title',
187+
'items.1',
188+
'items.1.title',
189+
])
190+
} else if (iterations === 3) {
191+
expect(Array.from(paths)).toEqual([
192+
'items',
193+
'items.0',
194+
'items.0.title',
195+
'items.1',
196+
'items.1.title',
197+
])
198+
}
199+
200+
if (!listener) {
201+
tree.addMutationListener(paths, trackPaths)
202+
}
203+
204+
iterations++
205+
}
206+
207+
trackPaths()
208+
tree.startMutationTracking()
209+
state.items.unshift({
210+
title: 'foo',
211+
})
212+
tree.clearMutationTracking()
213+
tree.flush()
214+
tree.startMutationTracking()
215+
state.items.unshift({
216+
title: 'bar',
217+
})
218+
tree.clearMutationTracking()
219+
tree.flush()
220+
tree.startMutationTracking()
221+
state.items[1].title = 'wapah'
222+
tree.clearMutationTracking()
223+
tree.flush()
224+
})
162225
})
163226

164227
describe('MUTATIONS', () => {

packages/node_modules/proxy-state-tree/src/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class ProxyStateTree {
1717
mutations: Mutation[]
1818
currentMutations: Mutation[]
1919
paths: Set<string>[]
20+
dirtyPaths: Set<string>
2021
status: STATUS
2122
proxy: any
2223
constructor(state: object, options: Options = { devmode: true }) {
@@ -26,6 +27,7 @@ class ProxyStateTree {
2627
this.mutations = []
2728
this.currentMutations = []
2829
this.paths = []
30+
this.dirtyPaths = new Set()
2931
this.status = STATUS.IDLE
3032
this.proxy = proxify(this, state)
3133
}
@@ -48,8 +50,19 @@ class ProxyStateTree {
4850
}
4951
}
5052
}
53+
for (let dirtyPath in this.dirtyPaths) {
54+
if (this.pathDependencies[dirtyPath]) {
55+
for (let callback of this.pathDependencies[dirtyPath]) {
56+
if (!pathCallbacksCalled.has(callback)) {
57+
pathCallbacksCalled.add(callback)
58+
callback()
59+
}
60+
}
61+
}
62+
}
5163
pathCallbacksCalled.clear()
5264
this.mutations.length = 0
65+
this.dirtyPaths.clear()
5366

5467
return mutations
5568
}

packages/node_modules/proxy-state-tree/src/proxify.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const isPlainObject = require('is-plain-object')
22

33
export const IS_PROXY = Symbol('IS_PROXY')
4+
export const PATH = Symbol('PATH')
5+
export const VALUE = Symbol('VALUE')
46

57
export enum STATUS {
68
IDLE = 'IDLE',
@@ -31,6 +33,8 @@ function createArrayProxy(tree, value, path) {
3133
return new Proxy(value, {
3234
get(target, prop) {
3335
if (prop === IS_PROXY) return true
36+
if (prop === PATH) return path
37+
if (prop === VALUE) return value
3438

3539
if (
3640
prop === 'length' ||
@@ -42,7 +46,6 @@ function createArrayProxy(tree, value, path) {
4246
}
4347

4448
const nestedPath = concat(path, prop)
45-
4649
if (tree.status === STATUS.TRACKING_PATHS) {
4750
tree.paths[tree.paths.length - 1].add(nestedPath)
4851
}
@@ -92,21 +95,22 @@ function createObjectProxy(tree, value, path) {
9295
return new Proxy(value, {
9396
get(target, prop) {
9497
if (prop === IS_PROXY) return true
98+
if (prop === PATH) return path
99+
if (prop === VALUE) return value
95100

96101
if (typeof prop === 'symbol') return target[prop]
97102

98-
const value = target[prop]
103+
const targetValue = target[prop]
99104
const nestedPath = concat(path, prop)
100-
101105
if (tree.status === STATUS.TRACKING_PATHS) {
102106
tree.paths[tree.paths.length - 1].add(nestedPath)
103107
}
104108

105-
if (typeof value === 'function') {
106-
return value(tree, nestedPath)
109+
if (typeof targetValue === 'function') {
110+
return targetValue(tree, nestedPath)
107111
}
108112

109-
return (target[prop] = proxify(tree, value, nestedPath))
113+
return (target[prop] = proxify(tree, targetValue, nestedPath))
110114
},
111115
set(target, prop, value) {
112116
const nestedPath = concat(path, prop)
@@ -151,7 +155,9 @@ function createObjectProxy(tree, value, path) {
151155

152156
function proxify(tree, value, path?) {
153157
if (value) {
154-
if (value[IS_PROXY]) {
158+
if (value[IS_PROXY] && value[PATH] !== path) {
159+
return proxify(tree, value[VALUE], path)
160+
} else if (value[IS_PROXY]) {
155161
return value
156162
} else if (Array.isArray(value)) {
157163
return createArrayProxy(tree, value, path)

0 commit comments

Comments
 (0)