Fixed bug with cache invalidation
Brian Vaughn committed
Apr 22, 2019 at 15:18 UTC
64bb2d31f91ea8234db6c6161c8256ade21180b9
3 files changed
+54
-37
src/devtools/ProfilingCache.js
+6
-3
@@ -1,6 +1,6 @@
1
// @flow
2
3
-import { createResource, invalidateResources } from './cache';
3
+import { createResource } from './cache';
4
import Store from './store';
5
import {
6
getCommitTree,
@@ -297,8 +297,11 @@ export default class ProfilingCache {
297
});
298
299
invalidate() {
300
- // Invalidate Susepnse caches.
301
- invalidateResources();
300
+ // Invalidate Suspense caches.
301
+ this.CommitDetails.clear();
302
+ this.FiberCommits.clear();
303
+ this.Interactions.clear();
304
+ this.ProfilingSummary.clear();
305
306
// Invalidate non-Suspense caches too.
307
invalidateCommitTrees();
src/devtools/cache.js
+26
-5
@@ -39,6 +39,7 @@ type RejectedResult = {|
39
type Result<Value> = PendingResult | ResolvedResult<Value> | RejectedResult;
40
41
export type Resource<Input, Key, Value> = {
42
+ clear(): void,
43
invalidate(Key): void,
44
read(Input): Value,
45
preload(Input): void,
@@ -66,7 +67,23 @@ function readContext(Context, observedBits) {
67
68
const CacheContext = createContext(null);
69
70
+type Config = {
71
+ useLRU?: boolean,
72
+};
73
+
74
const entries: Map<Resource<any, any, any>, Map<any, any>> = new Map();
75
+const resourceConfigs: Map<Resource<any, any, any>, Config> = new Map();
76
+
77
+function getEntriesForResource(resource: any): Map<any, any> {
78
+ let entriesForResource = ((entries.get(resource): any): Map<any, any>);
79
+ if (entriesForResource === undefined) {
80
+ const config = resourceConfigs.get(resource);
81
+ entriesForResource =
82
+ config !== undefined && config.useLRU ? new LRU({ max: 10 }) : new Map();
83
+ entries.set(resource, entriesForResource);
84
+ }
85
+ return entriesForResource;
86
+}
87
88
function accessResult<Input, Key, Value>(
89
resource: any,
@@ -74,7 +91,7 @@ function accessResult<Input, Key, Value>(
91
input: Input,
92
key: Key
93
): Result<Value> {
77
- const entriesForResource = ((entries.get(resource): any): Map<any, any>);
94
+ const entriesForResource = getEntriesForResource(resource);
95
const entry = entriesForResource.get(key);
96
if (entry === undefined) {
97
const thenable = fetch(input);
@@ -108,11 +125,15 @@ function accessResult<Input, Key, Value>(
125
export function createResource<Input, Key: string | number, Value>(
126
fetch: Input => Thenable<Value>,
127
hashInput: Input => Key,
111
- useLRU?: boolean = false
128
+ config?: Config = {}
129
): Resource<Input, Key, Value> {
130
const resource = {
131
+ clear(): void {
132
+ entries.delete(resource);
133
+ },
134
+
135
invalidate(key: Key): void {
115
- const entriesForResource = ((entries.get(resource): any): Map<any, any>);
136
+ const entriesForResource = getEntriesForResource(resource);
137
if (entriesForResource instanceof Map) {
138
entriesForResource.delete(key);
139
} else {
@@ -156,7 +177,7 @@ export function createResource<Input, Key: string | number, Value>(
177
},
178
179
write(key: Key, value: Value): void {
159
- const entriesForResource = ((entries.get(resource): any): Map<any, any>);
180
+ const entriesForResource = getEntriesForResource(resource);
181
182
const resolvedResult: ResolvedResult<Value> = {
183
status: Resolved,
@@ -167,7 +188,7 @@ export function createResource<Input, Key: string | number, Value>(
188
},
189
};
190
170
- entries.set(resource, useLRU ? new LRU({ max: 10 }) : new Map());
191
+ resourceConfigs.set(resource, config);
192
193
return resource;
194
}
src/devtools/views/Components/InspectedElementContext.js
+22
-29
@@ -31,6 +31,27 @@ type InProgressRequest = {|
31
resolveFn: ResolveFn,
32
|};
33
34
+const inProgressRequests: Map<number, InProgressRequest> = new Map();
35
+const resource: Resource<number, number, InspectedElement> = createResource(
36
+ (id: number) => {
37
+ let request = inProgressRequests.get(id);
38
+ if (request != null) {
39
+ return request.promise;
40
+ }
41
+
42
+ let resolveFn = ((null: any): ResolveFn);
43
+ const promise = new Promise(resolve => {
44
+ resolveFn = resolve;
45
+ });
46
+
47
+ inProgressRequests.set(id, { promise, resolveFn });
48
+
49
+ return promise;
50
+ },
51
+ (id: number) => id,
52
+ { useLRU: true }
53
+);
54
+
55
type Props = {|
56
children: React$Node,
57
|};
@@ -42,34 +63,6 @@ function InspectedElementContextController({ children }: Props) {
63
64
const [count, setCount] = useState<number>(0);
65
45
- const inProgressRequests = useMemo<Map<number, InProgressRequest>>(
46
- () => new Map(),
47
- []
48
- );
49
-
50
- const resource = useMemo<Resource<number, number, InspectedElement>>(
51
- () =>
52
- createResource(
53
- (id: number) => {
54
- let request = inProgressRequests.get(id);
55
- if (request != null) {
56
- return request.promise;
57
- }
58
-
59
- let resolveFn = ((null: any): ResolveFn);
60
- const promise = new Promise(resolve => {
61
- resolveFn = resolve;
62
- });
63
-
64
- inProgressRequests.set(id, { promise, resolveFn });
65
-
66
- return promise;
67
- },
68
- (id: number) => id
69
- ),
70
- [inProgressRequests]
71
- );
72
-
66
// This effect handler invalidates the suspense cache and schedules rendering updates with React.
67
useEffect(() => {
68
const onInspectedElement = (
@@ -103,7 +96,7 @@ function InspectedElementContextController({ children }: Props) {
96
97
bridge.addListener('inspectedElement', onInspectedElement);
98
return () => bridge.removeListener('inspectedElement', onInspectedElement);
106
- }, [bridge, inProgressRequests, inspectedElementID, resource]);
99
+ }, [bridge, inspectedElementID]);
100
101
// This effect handler polls for updates on the currently selected element.
102
useEffect(() => {