Skip to content

Commit 7f0d459

Browse files
authored
Use useSyncExternalStore() (#8785)
* add use-sync-external-store * Initial work on using useSyncExternalStore * fix useLazyQuery tests * update use-sync-external-store version * update timings to useMutation tests * change the timing in a Mutation component test which changed for no ostensible reason * fix the hoc tests agane * bring back the bad boy code block by popular demand * update useSyncExternalStore to handle ssr * use published useSyncExternalStore types * update dependencies and add beta to react peer range
1 parent 2b053c8 commit 7f0d459

22 files changed

+1111
-3262
lines changed

package-lock.json

Lines changed: 845 additions & 2976 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,19 @@
6464
},
6565
"peerDependencies": {
6666
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0",
67-
"react": "^16.8.0 || ^17.0.0",
68-
"subscriptions-transport-ws": "^0.9.0 || ^0.11.0"
67+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0-beta",
68+
"subscriptions-transport-ws": "^0.9.0 || ^0.11.0",
69+
"use-sync-external-store": "^1.0.0-beta-4ff5f5719-20211115"
6970
},
7071
"peerDependenciesMeta": {
7172
"react": {
7273
"optional": true
7374
},
7475
"subscriptions-transport-ws": {
7576
"optional": true
77+
},
78+
"use-sync-external-store": {
79+
"optional": true
7680
}
7781
},
7882
"dependencies": {
@@ -104,6 +108,7 @@
104108
"@types/node": "16.11.7",
105109
"@types/react": "17.0.34",
106110
"@types/react-dom": "17.0.2",
111+
"@types/use-sync-external-store": "^0.0.3",
107112
"bundlesize": "0.18.1",
108113
"cross-fetch": "3.1.4",
109114
"crypto-hash": "1.3.0",

src/link/persisted-queries/__tests__/react.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @jest-environment node */
12
import * as React from 'react';
23
import * as ReactDOM from 'react-dom/server';
34
import gql from 'graphql-tag';

src/react/components/__tests__/client/Mutation.test.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,11 @@ describe('General Mutation testing', () => {
10211021
return (
10221022
<Mutation mutation={mutation} refetchQueries={refetchQueries}>
10231023
{(createTodo: any, resultMutation: any) => (
1024-
<Query query={query} variables={variables}>
1024+
<Query
1025+
query={query}
1026+
variables={variables}
1027+
notifyOnNetworkStatusChange={true}
1028+
>
10251029
{(resultQuery: any) => {
10261030
try {
10271031
if (count === 0) {
@@ -1047,13 +1051,16 @@ describe('General Mutation testing', () => {
10471051
// mutation loading
10481052
expect(resultMutation.loading).toBe(true);
10491053
} else if (count === 6) {
1050-
// mutation loaded
1051-
expect(resultMutation.loading).toBe(false);
1054+
// mutation still loading???
1055+
expect(resultMutation.loading).toBe(true);
10521056
} else if (count === 7) {
1057+
expect(resultQuery.loading).toBe(true);
1058+
expect(resultMutation.loading).toBe(false);
1059+
} else if (count === 8) {
10531060
// query refetched
1061+
expect(resultQuery.data).toEqual(peopleData3);
10541062
expect(resultQuery.loading).toBe(false);
10551063
expect(resultMutation.loading).toBe(false);
1056-
expect(resultQuery.data).toEqual(peopleData3);
10571064
}
10581065
count++;
10591066
} catch (err) {
@@ -1074,7 +1081,7 @@ describe('General Mutation testing', () => {
10741081
);
10751082

10761083
waitFor(() => {
1077-
expect(count).toEqual(8);
1084+
expect(count).toBe(9);
10781085
}).then(resolve, reject);
10791086
}));
10801087

src/react/components/__tests__/client/Query.test.tsx

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,11 @@ describe('Query component', () => {
12311231
const { variables } = this.state;
12321232

12331233
return (
1234-
<AllPeopleQuery query={query} variables={variables}>
1234+
<AllPeopleQuery
1235+
query={query}
1236+
variables={variables}
1237+
notifyOnNetworkStatusChange={true}
1238+
>
12351239
{(result: any) => {
12361240
try {
12371241
switch (count) {
@@ -1719,35 +1723,40 @@ describe('Query component', () => {
17191723
<AllPeopleQuery
17201724
query={query}
17211725
variables={variables}
1726+
notifyOnNetworkStatusChange={true}
17221727
onCompleted={this.onCompleted}
17231728
>
17241729
{({ loading, data }: any) => {
1725-
switch (renderCount) {
1726-
case 0:
1727-
expect(loading).toBe(true);
1728-
break;
1729-
case 1:
1730-
case 2:
1731-
expect(loading).toBe(false);
1732-
expect(data).toEqual(data1);
1733-
break;
1734-
case 3:
1735-
expect(loading).toBe(true);
1736-
break;
1737-
case 4:
1738-
expect(loading).toBe(false);
1739-
expect(data).toEqual(data2);
1740-
setTimeout(() => {
1741-
this.setState({ variables: { first: 1 } });
1742-
});
1743-
case 5:
1744-
expect(loading).toBe(false);
1745-
expect(data).toEqual(data2);
1746-
break;
1747-
case 6:
1748-
expect(loading).toBe(false);
1749-
expect(data).toEqual(data1);
1750-
break;
1730+
try {
1731+
switch (renderCount) {
1732+
case 0:
1733+
expect(loading).toBe(true);
1734+
break;
1735+
case 1:
1736+
case 2:
1737+
expect(loading).toBe(false);
1738+
expect(data).toEqual(data1);
1739+
break;
1740+
case 3:
1741+
expect(loading).toBe(true);
1742+
break;
1743+
case 4:
1744+
expect(loading).toBe(false);
1745+
expect(data).toEqual(data2);
1746+
setTimeout(() => {
1747+
this.setState({ variables: { first: 1 } });
1748+
});
1749+
case 5:
1750+
expect(loading).toBe(false);
1751+
expect(data).toEqual(data2);
1752+
break;
1753+
case 6:
1754+
expect(loading).toBe(false);
1755+
expect(data).toEqual(data1);
1756+
break;
1757+
}
1758+
} catch (err) {
1759+
reject(err);
17511760
}
17521761
renderCount += 1;
17531762
return null;
@@ -1764,6 +1773,7 @@ describe('Query component', () => {
17641773
);
17651774

17661775
waitFor(() => {
1776+
expect(renderCount).toBe(7);
17671777
expect(onCompletedCallCount).toBe(3);
17681778
}).then(resolve, reject);
17691779
});

src/react/components/__tests__/ssr/getDataFromTree.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @jest-environment node */
12
import React from 'react';
23
import gql from 'graphql-tag';
34
import { DocumentNode } from 'graphql';

src/react/components/__tests__/ssr/server.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @jest-environment node */
12
import React from 'react';
23
import {
34
print,

src/react/hoc/__tests__/queries/errors.test.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,10 @@ describe('[queries] errors', () => {
216216
let iteration = 0;
217217
let done = false;
218218
const ErrorContainer = withState('var', 'setVar', 1)(
219-
graphql<Props, Data, Vars>(query)(
219+
graphql<Props, Data, Vars>(
220+
query,
221+
{ options: { notifyOnNetworkStatusChange: true }},
222+
)(
220223
class extends React.Component<ChildProps<Props, Data, Vars>> {
221224
componentDidUpdate() {
222225
const { props } = this;
@@ -234,7 +237,7 @@ describe('[queries] errors', () => {
234237
);
235238
} else if (iteration === 3) {
236239
// variables have changed, wee are loading again but also have data
237-
expect(props.data!.loading).toBeTruthy();
240+
expect(props.data!.loading).toBe(true);
238241
} else if (iteration === 4) {
239242
// the second request had an error!
240243
expect(props.data!.error).toBeTruthy();
@@ -256,8 +259,8 @@ describe('[queries] errors', () => {
256259
render() {
257260
return null;
258261
}
259-
}
260-
)
262+
},
263+
),
261264
);
262265

263266
render(
@@ -470,9 +473,11 @@ describe('[queries] errors', () => {
470473
});
471474
break;
472475
case 3:
476+
// Second render was added by useSyncExternalStore changes...
477+
case 4:
473478
expect(props.data!.loading).toBeTruthy();
474479
break;
475-
case 4:
480+
case 5:
476481
expect(props.data!.loading).toBeFalsy();
477482
expect(props.data!.error).toBeFalsy();
478483
expect(props.data!.allPeople).toEqual(
@@ -499,7 +504,7 @@ describe('[queries] errors', () => {
499504
</ApolloProvider>
500505
);
501506

502-
waitFor(() => expect(count).toBe(5)).then(resolve, reject);
507+
waitFor(() => expect(count).toBe(6)).then(resolve, reject);
503508
});
504509

505510
itAsync('does not throw/console.err an error after a component that received a network error is unmounted', (resolve, reject) => {

src/react/hoc/__tests__/queries/lifecycle.test.tsx

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ describe('[queries] lifecycle', () => {
4646
const Container = graphql<Vars, Data, Vars>(query, {
4747
options: props => ({
4848
variables: props,
49-
fetchPolicy: count === 0 ? 'cache-and-network' : 'cache-first'
49+
fetchPolicy: count === 0 ? 'cache-and-network' : 'cache-first',
50+
notifyOnNetworkStatusChange: true,
5051
})
5152
})(
5253
class extends React.Component<ChildProps<Vars, Data, Vars>> {
@@ -209,7 +210,10 @@ describe('[queries] lifecycle', () => {
209210
});
210211

211212
const Container = graphql<Vars, Data, Vars>(query, {
212-
options: props => ({ variables: props })
213+
options: props => ({
214+
variables: props,
215+
notifyOnNetworkStatusChange: true,
216+
}),
213217
})(
214218
class extends React.Component<ChildProps<Vars, Data, Vars>> {
215219
componentDidUpdate(prevProps: ChildProps<Vars, Data, Vars>) {
@@ -307,7 +311,10 @@ describe('[queries] lifecycle', () => {
307311
cache: new Cache({ addTypename: false })
308312
});
309313

310-
const Container = graphql<Vars, Data, Vars>(query)(
314+
const Container = graphql<Vars, Data, Vars>(
315+
query,
316+
{ options: { notifyOnNetworkStatusChange: true } },
317+
)(
311318
class extends React.Component<ChildProps<Vars, Data, Vars>> {
312319
componentDidUpdate(prevProps: ChildProps<Vars, Data, Vars>) {
313320
try {
@@ -794,11 +801,15 @@ describe('[queries] lifecycle', () => {
794801
}
795802

796803
render() {
797-
count++;
798-
const user = this.props.data!.user;
799-
const name = user ? user.name : '';
800-
if (count === 2) {
801-
expect(name).toBe('Luke Skywalker');
804+
try {
805+
count++;
806+
const user = this.props.data!.user;
807+
const name = user ? user.name : '';
808+
if (count === 3) {
809+
expect(name).toBe('Luke Skywalker');
810+
}
811+
} catch (err) {
812+
reject(err);
802813
}
803814
return null;
804815
}
@@ -873,26 +884,30 @@ describe('[queries] lifecycle', () => {
873884
<ApolloProvider client={client}>
874885
<QueryComponent query={query}>
875886
{({ loading, data, refetch }: any) => {
876-
if (!loading) {
877-
if (!refetched) {
878-
expect(data.books[0].name).toEqual('ssrfirst');
879-
//setTimeout allows component to mount, which often happens
880-
//when waiting ideally we should be able to call refetch
881-
//immediately However the subscription needs to start before
882-
//we update the data To get around this issue, we would need
883-
//to start the subscription before we render to the page. In
884-
//practice, this seems like an uncommon use case, since the
885-
//data you get is fresh, so one would wait for an interaction
886-
setTimeout(() => {
887-
refetch().then((refetchResult: any) => {
888-
expect(refetchResult.data.books[0].name).toEqual('first');
889-
done = true;
887+
try {
888+
if (!loading) {
889+
if (!refetched) {
890+
expect(data.books[0].name).toEqual('ssrfirst');
891+
//setTimeout allows component to mount, which often happens
892+
//when waiting ideally we should be able to call refetch
893+
//immediately However the subscription needs to start before
894+
//we update the data To get around this issue, we would need
895+
//to start the subscription before we render to the page. In
896+
//practice, this seems like an uncommon use case, since the
897+
//data you get is fresh, so one would wait for an interaction
898+
setTimeout(() => {
899+
refetch().then((refetchResult: any) => {
900+
expect(refetchResult.data.books[0].name).toEqual('first');
901+
done = true;
902+
});
890903
});
891-
});
892-
refetched = true;
893-
} else {
894-
expect(data.books[0].name).toEqual('first');
904+
refetched = true;
905+
} else {
906+
expect(data.books[0].name).toEqual('first');
907+
}
895908
}
909+
} catch (err) {
910+
reject(err);
896911
}
897912
return <p> stub </p>;
898913
}}

src/react/hoc/__tests__/queries/loading.test.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,10 @@ describe('[queries] loading', () => {
635635

636636
const Container = connect(
637637
graphql<Props, Data, Vars>(query, {
638-
options: ({ first }) => ({ variables: { first } })
638+
options: ({ first }) => ({
639+
variables: { first },
640+
notifyOnNetworkStatusChange: true,
641+
})
639642
})(
640643
class extends React.Component<ChildProps<Props, Data, Vars>> {
641644
render() {
@@ -754,7 +757,8 @@ describe('[queries] loading', () => {
754757
graphql<Props, Data, Vars>(query, {
755758
options: ({ first }) => ({
756759
variables: { first },
757-
fetchPolicy: 'network-only'
760+
fetchPolicy: 'network-only',
761+
notifyOnNetworkStatusChange: true,
758762
})
759763
})(
760764
class extends React.Component<ChildProps<Props, Data, Vars>> {
@@ -774,7 +778,6 @@ describe('[queries] loading', () => {
774778
expect(props.data!.loading).toBeFalsy(); // has initial data
775779
expect(props.data!.allPeople).toEqual(data.allPeople);
776780
break;
777-
778781
case 3:
779782
expect(props.data!.loading).toBeTruthy(); // on variables change
780783
break;

0 commit comments

Comments
 (0)