From 2340c24f4cc1348b2f4d498ab213c515bfb27620 Mon Sep 17 00:00:00 2001 From: jovi De Croock Date: Fri, 10 Jan 2020 14:42:42 +0100 Subject: [PATCH 1/4] add react-wonka --- package.json | 1 + src/hooks/useOperator.ts | 146 ----------------------------------- src/hooks/useQuery.ts | 2 +- src/hooks/useSubscription.ts | 2 +- tsconfig.json | 1 + yarn.lock | 5 ++ 6 files changed, 9 insertions(+), 148 deletions(-) delete mode 100644 src/hooks/useOperator.ts diff --git a/package.json b/package.json index 65e03c4736..6ac83c6dbf 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "scheduler": ">= 0.16.0" }, "dependencies": { + "react-wonka": "^2.0.0", "wonka": "^4.0.2" } } diff --git a/src/hooks/useOperator.ts b/src/hooks/useOperator.ts deleted file mode 100644 index 9b4d3afa53..0000000000 --- a/src/hooks/useOperator.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* eslint-disable @typescript-eslint/no-use-before-define */ -/* eslint-disable react-hooks/exhaustive-deps */ - -import { - useReducer, - useRef, - useEffect, - useLayoutEffect, - Dispatch, -} from 'react'; - -import { Subject, Operator, makeSubject, subscribe, pipe } from 'wonka'; - -import { - CallbackNode, - unstable_scheduleCallback as scheduleCallback, - unstable_cancelCallback as cancelCallback, - unstable_getCurrentPriorityLevel as getPriorityLevel, -} from 'scheduler'; - -type TeardownFn = () => void; - -interface State { - subject: Subject; - onValue: Dispatch; - teardown: null | TeardownFn; - task: null | CallbackNode; - value: R; -} - -const isServerSide = typeof window === 'undefined'; -const useIsomorphicEffect = !isServerSide ? useLayoutEffect : useEffect; - -/** - * Creates a stream of `input` as it's changing and pipes this stream - * into the operator which creates what becomes the output of this hook. - * - * This hooks supports creating a synchronous, stateful value that is - * updated immediately on mount and is then updated using normal effects. - * It has been built to be safe for normal-mode, concurrent-mode, - * strict-mode and suspense. - */ -export const useOperator = ( - operator: Operator, - input: T, - init?: R -): [R, Dispatch] => { - const subscription = useRef>({ - subject: makeSubject(), - value: init as R, - onValue: (value: R) => { - // Before the effect triggers we update the initial value synchronously - subscription.current.value = value; - }, - teardown: null, - task: null, - }); - - // This is called from effects to update the current output value - const [, setValue] = useReducer((x: number, value: R) => { - subscription.current.value = value; - return x + 1; - }, 0); - - // On mount, subscribe to the operator using the subject and schedule a teardown using scheduler (1) - if (subscription.current.teardown === null) { - observe( - operator, - subscription.current, - /* shouldScheduleTeardown */ !isServerSide - ); - // Send the initial input value to the operator; this may call `onValue` synchronously - subscription.current.subject.next(input); - if (isServerSide && subscription.current.teardown !== null) { - (subscription.current.teardown as any)(); - } - } - - // We utilise useLayoutEffect to cancel the scheduled teardown again - // This works because A) useLayoutEffect runs synchronously after mount - // during the commit phase, and B) if it runs we know that useEffect - // is also going to run. - useIsomorphicEffect(() => { - // Cancel the scheduled teardown - if (subscription.current.task !== null) { - cancelCallback(subscription.current.task); - } - - // On unmount we call the teardown manually to stop the subscription - return () => { - if (subscription.current.teardown !== null) { - subscription.current.teardown(); - } - }; - }, []); - - useEffect(() => { - const isInitial = subscription.current.onValue !== setValue; - // Once the effect runs, we update onValue to update this component properly - // instead of mutating - subscription.current.onValue = setValue; - - // If the subscription got cancelled, which may happen during long suspense phases (?), - // we restart it here without scheduling a teardown - if (subscription.current.teardown === null) { - observe( - operator, - subscription.current, - /* shouldScheduleTeardown */ false - ); - } - - // If the input value has changed (except during the initial mount) we send it to the operator - // This may call `setValue` which schedules an update - if (!isInitial) { - subscription.current.subject.next(input); - } - }, [input]); - - return [subscription.current.value, subscription.current.subject.next]; -}; - -const observe = ( - operator: Operator, - subscription: State, - shouldScheduleTeardown: boolean -) => { - // Start the subscription using the subject and operator - const { unsubscribe } = pipe( - operator(subscription.subject.source), - subscribe((value: R) => subscription.onValue(value)) - ); - - // Update the current teardown to now be the subscription's unsubcribe function - subscription.teardown = unsubscribe as TeardownFn; - - // See (1): We schedule a teardown on mount that is cancelled by useLayoutEffect, - // unless we're not expecting effects to run at all and the component not to be - // rendered, which means this callback won't be cancelled and will unsubscribe. - if (shouldScheduleTeardown) { - subscription.task = scheduleCallback( - getPriorityLevel(), - subscription.teardown - ); - } -}; diff --git a/src/hooks/useQuery.ts b/src/hooks/useQuery.ts index a3a8778118..c02462e426 100644 --- a/src/hooks/useQuery.ts +++ b/src/hooks/useQuery.ts @@ -1,12 +1,12 @@ import { DocumentNode } from 'graphql'; import { useCallback, useMemo } from 'react'; import { pipe, concat, fromValue, switchMap, map, scan } from 'wonka'; +import { useOperator } from 'react-wonka'; import { useClient } from '../context'; import { OperationContext, RequestPolicy } from '../types'; import { CombinedError } from '../utils'; import { useRequest } from './useRequest'; -import { useOperator } from './useOperator'; import { initialState } from './constants'; export interface UseQueryArgs { diff --git a/src/hooks/useSubscription.ts b/src/hooks/useSubscription.ts index a5a3efce9c..9a3377eb33 100644 --- a/src/hooks/useSubscription.ts +++ b/src/hooks/useSubscription.ts @@ -1,12 +1,12 @@ import { DocumentNode } from 'graphql'; import { useCallback, useRef, useMemo } from 'react'; import { pipe, concat, fromValue, switchMap, map, scan } from 'wonka'; +import { useOperator } from 'react-wonka'; import { useClient } from '../context'; import { CombinedError } from '../utils'; import { OperationContext } from '../types'; import { useRequest } from './useRequest'; -import { useOperator } from './useOperator'; import { initialState } from './constants'; export interface UseSubscriptionArgs { diff --git a/tsconfig.json b/tsconfig.json index 62ec2d99e5..d4c18a46c8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, "noUnusedLocals": true, "rootDir": "./src", "baseUrl": ".", diff --git a/yarn.lock b/yarn.lock index e9d8f5c956..884af8fd04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4666,6 +4666,11 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.11.0: react-is "^16.8.6" scheduler "^0.17.0" +react-wonka@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/react-wonka/-/react-wonka-2.0.0.tgz#d62d87c9c93ec3e603ecf1582df3615aadc5c2e9" + integrity sha512-7q0CNBnSltRyzb61joCxKqVntHbRJRhP/WPxEx+zM8l9Yd+0IRevJuPG8iCamgrGphusX5xtEtd4yyX7qvRM1g== + react@^16.11.0: version "16.11.0" resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb" From 7ae89431e34bd36603dae54b60fd6b74ac8d1e98 Mon Sep 17 00:00:00 2001 From: jovi De Croock Date: Fri, 10 Jan 2020 14:45:22 +0100 Subject: [PATCH 2/4] upgrade wonka --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ac83c6dbf..ccaae729c1 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,6 @@ }, "dependencies": { "react-wonka": "^2.0.0", - "wonka": "^4.0.2" + "wonka": "^4.0.3" } } From 74eee20e337f85a8fc1db61aa1fe68a1df35bc26 Mon Sep 17 00:00:00 2001 From: jovi De Croock Date: Fri, 10 Jan 2020 14:46:04 +0100 Subject: [PATCH 3/4] remove scheduler peerdep --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index ccaae729c1..5624d6e12f 100644 --- a/package.json +++ b/package.json @@ -134,8 +134,7 @@ }, "peerDependencies": { "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0", - "react": ">= 16.8.0", - "scheduler": ">= 0.16.0" + "react": ">= 16.8.0" }, "dependencies": { "react-wonka": "^2.0.0", From 2c63a5fbc8a75a6fdaf4a224bca29d921eebfb32 Mon Sep 17 00:00:00 2001 From: jovi De Croock Date: Fri, 10 Jan 2020 14:49:12 +0100 Subject: [PATCH 4/4] add lockfile --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 884af8fd04..ae52e7c01e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5935,10 +5935,10 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -wonka@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.2.tgz#32004bab7373da2150711fc703f7f12404dfdcb7" - integrity sha512-3Iwtr5agZFMs9j3c1fLn44FKi62G4XlNMbTluMbsF4fmJE6DDgVvkq7HwVOExWXOyGEfs8awOTTOebWbqG4quw== +wonka@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.3.tgz#95babdc479714232c11dcd99093ab2fee47842d8" + integrity sha512-lwSDBv375yZYC+P4sQxhZfF9izvtsdBZxRt4r5eHLmJdCFjQu500zqSO73rxXpRuoPgJtS3/BCiwOxHcBeftjg== wordwrap@~0.0.2: version "0.0.3"