@isograph/react 0.0.0-main-0a7c1aef → 0.0.0-main-d319cfe5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/IsographEnvironment.d.ts +10 -6
- package/dist/IsographEnvironment.js +1 -1
- package/dist/componentCache.d.ts +1 -1
- package/dist/componentCache.js +7 -4
- package/dist/read.d.ts +2 -2
- package/dist/read.js +22 -2
- package/dist/reader.d.ts +2 -0
- package/dist/useRerenderWhenEncounteredRecordChanges.js +3 -4
- package/package.json +3 -3
- package/src/IsographEnvironment.tsx +16 -6
- package/src/componentCache.ts +15 -6
- package/src/read.ts +32 -1
- package/src/reader.ts +4 -0
- package/src/tests/__isograph/Query/meName/reader.ts +1 -0
- package/src/tests/__isograph/Query/meNameSuccessor/reader.ts +1 -0
- package/src/tests/__isograph/Query/nodeField/reader.ts +1 -0
- package/src/useRerenderWhenEncounteredRecordChanges.ts +3 -4
@@ -1,15 +1,19 @@
|
|
1
1
|
/// <reference types="react" />
|
2
2
|
import { ParentCache } from '@isograph/react-disposable-state';
|
3
3
|
import { RetainedQuery } from './garbageCollection';
|
4
|
-
type
|
4
|
+
export type ComponentOrFieldName = string;
|
5
5
|
type StringifiedArgs = string;
|
6
|
-
type
|
6
|
+
type ComponentAndEncounteredRecordsCache = {
|
7
7
|
[key: DataId]: {
|
8
|
-
[key:
|
9
|
-
[key: StringifiedArgs]:
|
8
|
+
[key: ComponentOrFieldName]: {
|
9
|
+
[key: StringifiedArgs]: ComponentAndEncounteredRecords;
|
10
10
|
};
|
11
11
|
};
|
12
12
|
};
|
13
|
+
export type ComponentAndEncounteredRecords = {
|
14
|
+
component: React.FC<any>;
|
15
|
+
encounteredRecordsDuringLastRead: Set<DataId> | null;
|
16
|
+
};
|
13
17
|
type CallbackAndRecords = {
|
14
18
|
callback: () => void;
|
15
19
|
records: Set<DataId> | null;
|
@@ -22,12 +26,12 @@ export type IsographEnvironment = {
|
|
22
26
|
store: IsographStore;
|
23
27
|
networkFunction: IsographNetworkFunction;
|
24
28
|
missingFieldHandler: MissingFieldHandler | null;
|
25
|
-
componentCache: ComponentCache;
|
26
29
|
subscriptions: Subscriptions;
|
27
|
-
suspenseCache: SuspenseCache;
|
28
30
|
retainedQueries: Set<RetainedQuery>;
|
29
31
|
gcBuffer: Array<RetainedQuery>;
|
30
32
|
gcBufferSize: number;
|
33
|
+
componentAndEncounteredRecordsCache: ComponentAndEncounteredRecordsCache;
|
34
|
+
suspenseCache: SuspenseCache;
|
31
35
|
};
|
32
36
|
export type MissingFieldHandler = (storeRecord: StoreRecord, root: DataId, fieldName: string, arguments_: {
|
33
37
|
[index: string]: any;
|
@@ -8,7 +8,7 @@ function createIsographEnvironment(store, networkFunction, missingFieldHandler)
|
|
8
8
|
store,
|
9
9
|
networkFunction,
|
10
10
|
missingFieldHandler: missingFieldHandler !== null && missingFieldHandler !== void 0 ? missingFieldHandler : null,
|
11
|
-
|
11
|
+
componentAndEncounteredRecordsCache: {},
|
12
12
|
subscriptions: new Set(),
|
13
13
|
suspenseCache: {},
|
14
14
|
retainedQueries: new Set(),
|
package/dist/componentCache.d.ts
CHANGED
@@ -4,4 +4,4 @@ import { IsographEnvironment, DataId } from './IsographEnvironment';
|
|
4
4
|
import { ReaderArtifact } from './reader';
|
5
5
|
export declare function getOrCreateCachedComponent(environment: IsographEnvironment, rootId: DataId, componentName: string, readerArtifact: ReaderArtifact<any, any>, variables: {
|
6
6
|
[key: string]: string;
|
7
|
-
}, resolverRefetchQueries: RefetchQueryArtifactWrapper[]):
|
7
|
+
}, resolverRefetchQueries: RefetchQueryArtifactWrapper[]): React.FC<any>;
|
package/dist/componentCache.js
CHANGED
@@ -6,7 +6,7 @@ const read_1 = require("./read");
|
|
6
6
|
const useRerenderWhenEncounteredRecordChanges_1 = require("./useRerenderWhenEncounteredRecordChanges");
|
7
7
|
function getOrCreateCachedComponent(environment, rootId, componentName, readerArtifact, variables, resolverRefetchQueries) {
|
8
8
|
var _a, _b, _c;
|
9
|
-
const cachedComponentsById = environment.
|
9
|
+
const cachedComponentsById = environment.componentAndEncounteredRecordsCache;
|
10
10
|
const stringifiedArgs = JSON.stringify((0, cache_1.stableCopy)(variables));
|
11
11
|
cachedComponentsById[rootId] = (_a = cachedComponentsById[rootId]) !== null && _a !== void 0 ? _a : {};
|
12
12
|
const componentsByName = cachedComponentsById[rootId];
|
@@ -21,7 +21,7 @@ function getOrCreateCachedComponent(environment, rootId, componentName, readerAr
|
|
21
21
|
root: rootId,
|
22
22
|
variables,
|
23
23
|
nestedRefetchQueries: resolverRefetchQueries,
|
24
|
-
});
|
24
|
+
}, byArgs[stringifiedArgs]);
|
25
25
|
(0, useRerenderWhenEncounteredRecordChanges_1.useRerenderWhenEncounteredRecordChanges)(environment, encounteredRecords);
|
26
26
|
if (typeof window !== 'undefined' && window.__LOG) {
|
27
27
|
console.log('Component re-rendered: ' + componentName + ' ' + rootId);
|
@@ -29,8 +29,11 @@ function getOrCreateCachedComponent(environment, rootId, componentName, readerAr
|
|
29
29
|
return readerArtifact.resolver(data, additionalRuntimeProps);
|
30
30
|
}
|
31
31
|
Component.displayName = `${componentName} (id: ${rootId}) @component`;
|
32
|
-
return
|
32
|
+
return {
|
33
|
+
component: Component,
|
34
|
+
encounteredRecordsDuringLastRead: null,
|
35
|
+
};
|
33
36
|
})();
|
34
|
-
return byArgs[stringifiedArgs];
|
37
|
+
return byArgs[stringifiedArgs].component;
|
35
38
|
}
|
36
39
|
exports.getOrCreateCachedComponent = getOrCreateCachedComponent;
|
package/dist/read.d.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import { FragmentReference } from './FragmentReference';
|
2
|
-
import { DataId, IsographEnvironment } from './IsographEnvironment';
|
2
|
+
import { ComponentAndEncounteredRecords, DataId, IsographEnvironment } from './IsographEnvironment';
|
3
3
|
export type WithEncounteredRecords<T> = {
|
4
4
|
encounteredRecords: Set<DataId>;
|
5
5
|
item: T;
|
6
6
|
};
|
7
7
|
export declare function read<TReadFromStore extends Object, TClientFieldValue>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>): WithEncounteredRecords<TClientFieldValue>;
|
8
|
-
export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, reference: FragmentReference<TReadFromStore, unknown
|
8
|
+
export declare function readButDoNotEvaluate<TReadFromStore extends Object>(environment: IsographEnvironment, reference: FragmentReference<TReadFromStore, unknown>, encounteredRecordCache: ComponentAndEncounteredRecords): WithEncounteredRecords<TReadFromStore>;
|
package/dist/read.js
CHANGED
@@ -32,7 +32,7 @@ function read(environment, fragmentReference) {
|
|
32
32
|
throw new Error('This is unreachable');
|
33
33
|
}
|
34
34
|
exports.read = read;
|
35
|
-
function readButDoNotEvaluate(environment, reference) {
|
35
|
+
function readButDoNotEvaluate(environment, reference, encounteredRecordCache) {
|
36
36
|
var _a;
|
37
37
|
const mutableEncounteredRecords = new Set();
|
38
38
|
const response = readData(environment, reference.readerArtifact.readerAst, reference.root, (_a = reference.variables) !== null && _a !== void 0 ? _a : {}, reference.nestedRefetchQueries, mutableEncounteredRecords);
|
@@ -43,13 +43,33 @@ function readButDoNotEvaluate(environment, reference) {
|
|
43
43
|
throw (0, cache_1.onNextChange)(environment);
|
44
44
|
}
|
45
45
|
else {
|
46
|
+
const encounteredRecords = compareAndUpdateEncounteredRecords(encounteredRecordCache, mutableEncounteredRecords);
|
46
47
|
return {
|
47
|
-
encounteredRecords
|
48
|
+
encounteredRecords,
|
48
49
|
item: response.data,
|
49
50
|
};
|
50
51
|
}
|
51
52
|
}
|
52
53
|
exports.readButDoNotEvaluate = readButDoNotEvaluate;
|
54
|
+
function compareAndUpdateEncounteredRecords(encounteredRecordCache, newEncounteredRecords) {
|
55
|
+
const { encounteredRecordsDuringLastRead } = encounteredRecordCache;
|
56
|
+
if (encounteredRecordsDuringLastRead == null ||
|
57
|
+
encounteredRecordsDuringLastRead.size != newEncounteredRecords.size) {
|
58
|
+
encounteredRecordCache.encounteredRecordsDuringLastRead =
|
59
|
+
newEncounteredRecords;
|
60
|
+
return newEncounteredRecords;
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
for (const item of newEncounteredRecords) {
|
64
|
+
if (!encounteredRecordsDuringLastRead.has(item)) {
|
65
|
+
encounteredRecordCache.encounteredRecordsDuringLastRead =
|
66
|
+
newEncounteredRecords;
|
67
|
+
return newEncounteredRecords;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
return encounteredRecordsDuringLastRead;
|
71
|
+
}
|
72
|
+
}
|
53
73
|
function readData(environment, ast, root, variables, nestedRefetchQueries, mutableEncounteredRecords) {
|
54
74
|
var _a, _b, _c, _d, _e;
|
55
75
|
mutableEncounteredRecords.add(root);
|
package/dist/reader.d.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
import { ComponentOrFieldName } from './IsographEnvironment';
|
1
2
|
import { Arguments } from './util';
|
2
3
|
export type ReaderArtifact<TReadFromStore extends Object, TClientFieldValue> = {
|
3
4
|
kind: 'ReaderArtifact';
|
5
|
+
fieldName: ComponentOrFieldName;
|
4
6
|
readerAst: ReaderAst<TReadFromStore>;
|
5
7
|
resolver: (data: TReadFromStore, runtimeProps: any) => TClientFieldValue;
|
6
8
|
variant: ReaderResolverVariant;
|
@@ -3,15 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useRerenderWhenEncounteredRecordChanges = void 0;
|
4
4
|
const react_1 = require("react");
|
5
5
|
const cache_1 = require("./cache");
|
6
|
+
// TODO add unit tests for this. Add integration tests that test
|
7
|
+
// behavior when the encounteredRecords underneath a fragment change.
|
6
8
|
function useRerenderWhenEncounteredRecordChanges(environment, encounteredRecords) {
|
7
9
|
const [, setState] = (0, react_1.useState)();
|
8
10
|
(0, react_1.useEffect)(() => {
|
9
11
|
return (0, cache_1.subscribe)(environment, encounteredRecords, () => {
|
10
12
|
return setState({});
|
11
13
|
});
|
12
|
-
|
13
|
-
// encounteredRecords changes. However, it is not a stable object, so...
|
14
|
-
// how?
|
15
|
-
}, []);
|
14
|
+
}, [encounteredRecords]);
|
16
15
|
}
|
17
16
|
exports.useRerenderWhenEncounteredRecordChanges = useRerenderWhenEncounteredRecordChanges;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@isograph/react",
|
3
|
-
"version": "0.0.0-main-
|
3
|
+
"version": "0.0.0-main-d319cfe5",
|
4
4
|
"description": "Use Isograph with React",
|
5
5
|
"homepage": "https://isograph.dev",
|
6
6
|
"main": "dist/index.js",
|
@@ -16,8 +16,8 @@
|
|
16
16
|
"prepack": "yarn run test && yarn run compile"
|
17
17
|
},
|
18
18
|
"dependencies": {
|
19
|
-
"@isograph/disposable-types": "0.0.0-main-
|
20
|
-
"@isograph/react-disposable-state": "0.0.0-main-
|
19
|
+
"@isograph/disposable-types": "0.0.0-main-d319cfe5",
|
20
|
+
"@isograph/react-disposable-state": "0.0.0-main-d319cfe5",
|
21
21
|
"react": "^18.2.0"
|
22
22
|
},
|
23
23
|
"devDependencies": {
|
@@ -1,14 +1,22 @@
|
|
1
1
|
import { ParentCache } from '@isograph/react-disposable-state';
|
2
2
|
import { RetainedQuery } from './garbageCollection';
|
3
3
|
|
4
|
-
type
|
4
|
+
export type ComponentOrFieldName = string;
|
5
5
|
type StringifiedArgs = string;
|
6
|
-
type
|
6
|
+
type ComponentAndEncounteredRecordsCache = {
|
7
7
|
[key: DataId]: {
|
8
|
-
[key:
|
8
|
+
[key: ComponentOrFieldName]: {
|
9
|
+
[key: StringifiedArgs]: ComponentAndEncounteredRecords;
|
10
|
+
};
|
9
11
|
};
|
10
12
|
};
|
11
13
|
|
14
|
+
export type ComponentAndEncounteredRecords = {
|
15
|
+
component: React.FC<any>;
|
16
|
+
// null if we have never read before
|
17
|
+
encounteredRecordsDuringLastRead: Set<DataId> | null;
|
18
|
+
};
|
19
|
+
|
12
20
|
type CallbackAndRecords = {
|
13
21
|
callback: () => void;
|
14
22
|
records: Set<DataId> | null;
|
@@ -20,12 +28,14 @@ export type IsographEnvironment = {
|
|
20
28
|
store: IsographStore;
|
21
29
|
networkFunction: IsographNetworkFunction;
|
22
30
|
missingFieldHandler: MissingFieldHandler | null;
|
23
|
-
componentCache: ComponentCache;
|
24
31
|
subscriptions: Subscriptions;
|
25
|
-
suspenseCache: SuspenseCache;
|
26
32
|
retainedQueries: Set<RetainedQuery>;
|
27
33
|
gcBuffer: Array<RetainedQuery>;
|
28
34
|
gcBufferSize: number;
|
35
|
+
|
36
|
+
// These caches should be moved into the store somehow
|
37
|
+
componentAndEncounteredRecordsCache: ComponentAndEncounteredRecordsCache;
|
38
|
+
suspenseCache: SuspenseCache;
|
29
39
|
};
|
30
40
|
|
31
41
|
export type MissingFieldHandler = (
|
@@ -85,7 +95,7 @@ export function createIsographEnvironment(
|
|
85
95
|
store,
|
86
96
|
networkFunction,
|
87
97
|
missingFieldHandler: missingFieldHandler ?? null,
|
88
|
-
|
98
|
+
componentAndEncounteredRecordsCache: {},
|
89
99
|
subscriptions: new Set(),
|
90
100
|
suspenseCache: {},
|
91
101
|
retainedQueries: new Set(),
|
package/src/componentCache.ts
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
import { stableCopy } from './cache';
|
2
2
|
import { RefetchQueryArtifactWrapper } from './entrypoint';
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
IsographEnvironment,
|
5
|
+
DataId,
|
6
|
+
ComponentAndEncounteredRecords,
|
7
|
+
} from './IsographEnvironment';
|
4
8
|
import { readButDoNotEvaluate } from './read';
|
5
9
|
import { ReaderArtifact } from './reader';
|
6
10
|
import { useRerenderWhenEncounteredRecordChanges } from './useRerenderWhenEncounteredRecordChanges';
|
@@ -12,8 +16,8 @@ export function getOrCreateCachedComponent(
|
|
12
16
|
readerArtifact: ReaderArtifact<any, any>,
|
13
17
|
variables: { [key: string]: string },
|
14
18
|
resolverRefetchQueries: RefetchQueryArtifactWrapper[],
|
15
|
-
) {
|
16
|
-
const cachedComponentsById = environment.
|
19
|
+
): React.FC<any> {
|
20
|
+
const cachedComponentsById = environment.componentAndEncounteredRecordsCache;
|
17
21
|
const stringifiedArgs = JSON.stringify(stableCopy(variables));
|
18
22
|
cachedComponentsById[rootId] = cachedComponentsById[rootId] ?? {};
|
19
23
|
const componentsByName = cachedComponentsById[rootId];
|
@@ -21,7 +25,7 @@ export function getOrCreateCachedComponent(
|
|
21
25
|
const byArgs = componentsByName[componentName];
|
22
26
|
byArgs[stringifiedArgs] =
|
23
27
|
byArgs[stringifiedArgs] ??
|
24
|
-
(() => {
|
28
|
+
((): ComponentAndEncounteredRecords => {
|
25
29
|
function Component(additionalRuntimeProps: { [key: string]: any }) {
|
26
30
|
const { item: data, encounteredRecords } = readButDoNotEvaluate(
|
27
31
|
environment,
|
@@ -32,6 +36,7 @@ export function getOrCreateCachedComponent(
|
|
32
36
|
variables,
|
33
37
|
nestedRefetchQueries: resolverRefetchQueries,
|
34
38
|
},
|
39
|
+
byArgs[stringifiedArgs],
|
35
40
|
);
|
36
41
|
|
37
42
|
useRerenderWhenEncounteredRecordChanges(
|
@@ -46,7 +51,11 @@ export function getOrCreateCachedComponent(
|
|
46
51
|
return readerArtifact.resolver(data, additionalRuntimeProps);
|
47
52
|
}
|
48
53
|
Component.displayName = `${componentName} (id: ${rootId}) @component`;
|
49
|
-
return
|
54
|
+
return {
|
55
|
+
component: Component,
|
56
|
+
encounteredRecordsDuringLastRead: null,
|
57
|
+
};
|
50
58
|
})();
|
51
|
-
|
59
|
+
|
60
|
+
return byArgs[stringifiedArgs].component;
|
52
61
|
}
|
package/src/read.ts
CHANGED
@@ -4,6 +4,7 @@ import { RefetchQueryArtifactWrapper } from './entrypoint';
|
|
4
4
|
import { FragmentReference } from './FragmentReference';
|
5
5
|
import {
|
6
6
|
assertLink,
|
7
|
+
ComponentAndEncounteredRecords,
|
7
8
|
DataId,
|
8
9
|
defaultMissingFieldHandler,
|
9
10
|
IsographEnvironment,
|
@@ -60,6 +61,7 @@ export function read<TReadFromStore extends Object, TClientFieldValue>(
|
|
60
61
|
export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
61
62
|
environment: IsographEnvironment,
|
62
63
|
reference: FragmentReference<TReadFromStore, unknown>,
|
64
|
+
encounteredRecordCache: ComponentAndEncounteredRecords,
|
63
65
|
): WithEncounteredRecords<TReadFromStore> {
|
64
66
|
const mutableEncounteredRecords = new Set<DataId>();
|
65
67
|
const response = readData(
|
@@ -76,13 +78,42 @@ export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
|
76
78
|
if (response.kind === 'MissingData') {
|
77
79
|
throw onNextChange(environment);
|
78
80
|
} else {
|
81
|
+
const encounteredRecords = compareAndUpdateEncounteredRecords(
|
82
|
+
encounteredRecordCache,
|
83
|
+
mutableEncounteredRecords,
|
84
|
+
);
|
85
|
+
|
79
86
|
return {
|
80
|
-
encounteredRecords
|
87
|
+
encounteredRecords,
|
81
88
|
item: response.data,
|
82
89
|
};
|
83
90
|
}
|
84
91
|
}
|
85
92
|
|
93
|
+
function compareAndUpdateEncounteredRecords(
|
94
|
+
encounteredRecordCache: ComponentAndEncounteredRecords,
|
95
|
+
newEncounteredRecords: Set<DataId>,
|
96
|
+
): Set<DataId> {
|
97
|
+
const { encounteredRecordsDuringLastRead } = encounteredRecordCache;
|
98
|
+
if (
|
99
|
+
encounteredRecordsDuringLastRead == null ||
|
100
|
+
encounteredRecordsDuringLastRead.size != newEncounteredRecords.size
|
101
|
+
) {
|
102
|
+
encounteredRecordCache.encounteredRecordsDuringLastRead =
|
103
|
+
newEncounteredRecords;
|
104
|
+
return newEncounteredRecords;
|
105
|
+
} else {
|
106
|
+
for (const item of newEncounteredRecords) {
|
107
|
+
if (!encounteredRecordsDuringLastRead.has(item)) {
|
108
|
+
encounteredRecordCache.encounteredRecordsDuringLastRead =
|
109
|
+
newEncounteredRecords;
|
110
|
+
return newEncounteredRecords;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
return encounteredRecordsDuringLastRead;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
86
117
|
type ReadDataResult<TReadFromStore> =
|
87
118
|
| {
|
88
119
|
kind: 'Success';
|
package/src/reader.ts
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
import { ComponentOrFieldName } from './IsographEnvironment';
|
1
2
|
import { Arguments } from './util';
|
2
3
|
|
3
4
|
// TODO this should probably be at least three distinct types, for @component,
|
4
5
|
// non-@component and refetch resolvers
|
5
6
|
export type ReaderArtifact<TReadFromStore extends Object, TClientFieldValue> = {
|
6
7
|
kind: 'ReaderArtifact';
|
8
|
+
// The DataID of the parent + the fieldName + the variables are enough
|
9
|
+
// to uniquely identify a call to read(...) at a given time.
|
10
|
+
fieldName: ComponentOrFieldName;
|
7
11
|
readerAst: ReaderAst<TReadFromStore>;
|
8
12
|
resolver: (data: TReadFromStore, runtimeProps: any) => TClientFieldValue;
|
9
13
|
variant: ReaderResolverVariant;
|
@@ -2,6 +2,8 @@ import { useEffect, useState } from 'react';
|
|
2
2
|
import { DataId, IsographEnvironment } from './IsographEnvironment';
|
3
3
|
import { subscribe } from './cache';
|
4
4
|
|
5
|
+
// TODO add unit tests for this. Add integration tests that test
|
6
|
+
// behavior when the encounteredRecords underneath a fragment change.
|
5
7
|
export function useRerenderWhenEncounteredRecordChanges(
|
6
8
|
environment: IsographEnvironment,
|
7
9
|
encounteredRecords: Set<DataId>,
|
@@ -11,8 +13,5 @@ export function useRerenderWhenEncounteredRecordChanges(
|
|
11
13
|
return subscribe(environment, encounteredRecords, () => {
|
12
14
|
return setState({});
|
13
15
|
});
|
14
|
-
|
15
|
-
// encounteredRecords changes. However, it is not a stable object, so...
|
16
|
-
// how?
|
17
|
-
}, []);
|
16
|
+
}, [encounteredRecords]);
|
18
17
|
}
|