@samitouri / QOS-React / commits / 64bb2d31f9

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(() => {