diff --git a/package-lock.json b/package-lock.json
index 5f12c77..fea9a45 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "replicache-react",
- "version": "3.1.0",
+ "version": "4.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "replicache-react",
- "version": "3.1.0",
+ "version": "4.0.0",
"license": "ISC",
"devDependencies": {
"@esm-bundle/chai": "^4.3.4-fix.0",
diff --git a/package.json b/package.json
index 767ecd5..f01119c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "replicache-react",
- "version": "3.1.0",
+ "version": "4.0.0",
"description": "Miscellaneous utilities for using Replicache with React",
"homepage": "https://replicache.dev",
"repository": "github:rocicorp/replicache-react",
diff --git a/src/index.test.tsx b/src/index.test.tsx
index b4e843c..a091495 100644
--- a/src/index.test.tsx
+++ b/src/index.test.tsx
@@ -76,7 +76,7 @@ test('Batching of subscriptions', async () => {
const dataA = useSubscribe(
rep,
// TODO: Use type param to get when new Replicache is released.
- async tx => ((await tx.get('a')) as string | undefined) ?? null,
+ async tx => (await tx.get('a')) as string | undefined,
null,
);
renderLog.push('render A', dataA);
@@ -86,7 +86,7 @@ test('Batching of subscriptions', async () => {
function B({rep, dataA}: {rep: MyRep; dataA: string | null}) {
const dataB = useSubscribe(
rep,
- async tx => ((await tx.get('b')) as string | undefined) ?? null,
+ async tx => (await tx.get('b')) as string | undefined,
null,
);
renderLog.push('render B', dataA, dataB);
@@ -129,7 +129,7 @@ test('returning undefined', async () => {
},
def,
);
- return
{subResult === undefined ? 'undefined' : 'defined'}
;
+ return {subResult}
;
}
const div = document.createElement('div');
@@ -141,10 +141,10 @@ test('returning undefined', async () => {
});
render(, div);
- expect(div.textContent).to.equal('defined');
+ expect(div.textContent).to.equal('default');
await promise;
await sleep(1);
- expect(div.textContent).to.equal('undefined');
+ expect(div.textContent).to.equal('default');
await rep.close();
});
diff --git a/src/index.ts b/src/index.ts
index 5452efb..7d14138 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -25,13 +25,15 @@ function doCallback() {
});
}
-export function useSubscribe(
- r: Subscribable | null | undefined,
- query: (tx: Tx) => Promise,
- def: R,
+export type RemoveUndefined = T extends undefined ? never : T;
+
+export function useSubscribe(
+ r: Subscribable | null | undefined,
+ query: (tx: Tx) => Promise,
+ def: Default,
deps: Array = [],
-): R {
- const [snapshot, setSnapshot] = useState(def);
+) {
+ const [snapshot, setSnapshot] = useState(undefined);
useEffect(() => {
if (!r) {
return;
@@ -41,7 +43,7 @@ export function useSubscribe(
onData: data => {
// This is safe because we know that subscribe in fact can only return
// `R` (the return type of query or def).
- callbacks.push(() => setSnapshot(data as R));
+ callbacks.push(() => setSnapshot(data as QueryRet));
if (!hasPendingCallback) {
void Promise.resolve().then(doCallback);
hasPendingCallback = true;
@@ -51,8 +53,15 @@ export function useSubscribe(
return () => {
unsubscribe();
- setSnapshot(def);
+ setSnapshot(undefined);
};
- }, [r, ...deps]);
- return snapshot;
+ }, [r, def, ...deps]);
+ if (snapshot === undefined) {
+ return def;
+ }
+ // This RemoveUndefined is just here to make the return type easier to read.
+ // It should be exactly equivalent to what the type would be without this.
+ // For some reason declaring the return type to be
+ // RemoveUndefined | Default doesn't typecheck.
+ return snapshot as RemoveUndefined;
}