Skip to content

Commit

Permalink
Implement useFragment hook.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamn committed Sep 17, 2021
1 parent 2a8f136 commit 7c21f05
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 9 deletions.
3 changes: 3 additions & 0 deletions src/__tests__/__snapshots__/exports.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Array [
"throwServerError",
"toPromise",
"useApolloClient",
"useFragment",
"useLazyQuery",
"useMutation",
"useQuery",
Expand Down Expand Up @@ -235,6 +236,7 @@ Array [
"parser",
"resetApolloContext",
"useApolloClient",
"useFragment",
"useLazyQuery",
"useMutation",
"useQuery",
Expand Down Expand Up @@ -273,6 +275,7 @@ Array [
exports[`exports of public entry points @apollo/client/react/hooks 1`] = `
Array [
"useApolloClient",
"useFragment",
"useLazyQuery",
"useMutation",
"useQuery",
Expand Down
4 changes: 2 additions & 2 deletions src/cache/core/types/Cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export namespace Cache {
export interface DiffOptions<
TData = any,
TVariables = any,
> extends ReadOptions<TVariables, TData> {
> extends Omit<ReadOptions<TVariables, TData>, "rootId"> {
// The DiffOptions interface is currently just an alias for
// ReadOptions, though DiffOptions used to be responsible for
// declaring the returnPartialData option.
Expand All @@ -37,7 +37,7 @@ export namespace Cache {
export interface WatchOptions<
TData = any,
TVariables = any,
> extends ReadOptions<TVariables, TData> {
> extends DiffOptions<TData, TVariables> {
watcher?: object;
immediate?: boolean;
callback: WatchCallback<TData>;
Expand Down
10 changes: 3 additions & 7 deletions src/cache/inmemory/inMemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
// currently using a data store that can track cache dependencies.
const store = c.optimistic ? this.optimisticData : this.data;
if (supportsResultCaching(store)) {
const { optimistic, rootId, variables } = c;
const { optimistic, id, variables } = c;
return store.makeCacheKey(
c.query,
// Different watches can have the same query, optimistic
Expand All @@ -151,7 +151,7 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
// separation is to include c.callback in the cache key for
// maybeBroadcastWatch calls. See issue #5733.
c.callback,
canonicalStringify({ optimistic, rootId, variables }),
canonicalStringify({ optimistic, id, variables }),
);
}
}
Expand Down Expand Up @@ -532,11 +532,7 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
options?: BroadcastOptions,
) {
const { lastDiff } = c;
const diff = this.diff<any>({
query: c.query,
variables: c.variables,
optimistic: c.optimistic,
});
const diff = this.diff<any>(c);

if (options) {
if (c.optimistic &&
Expand Down
1 change: 1 addition & 0 deletions src/react/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './useMutation';
export * from './useQuery';
export * from './useSubscription';
export * from './useReactiveVar';
export * from './useFragment';
70 changes: 70 additions & 0 deletions src/react/hooks/useFragment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useEffect, useState } from "react";
import { equal } from "@wry/equality";

import { Cache, MissingFieldError, Reference, StoreObject } from "../../cache";
import { useApolloClient } from "./useApolloClient";

export interface UseFragmentOptions<TData, TVars>
extends Omit<
Cache.DiffOptions<TData, TVars>,
| "id"
| "query"
| "optimistic"
>, Omit<
Cache.ReadFragmentOptions<TData, TVars>,
| "id"
> {
from: StoreObject | Reference | string;
// Override this field to make it optional (default: true).
optimistic?: boolean;
}

export interface UseFragmentResult<TData> {
data: TData | undefined,
complete: boolean,
missing: MissingFieldError[] | undefined;
}

export function useFragment<TData, TVars>(
options: UseFragmentOptions<TData, TVars>,
): UseFragmentResult<TData> {
const { cache } = useApolloClient();

const {
fragment,
fragmentName,
from,
optimistic = true,
...rest
} = options;

const diffOptions: Cache.DiffOptions<TData, TVars> = {
...rest,
id: typeof from === "string" ? from : cache.identify(from),
query: cache["getFragmentDoc"](fragment, fragmentName),
optimistic,
};

const preDiff = cache.diff<TData>(diffOptions);
const setDiff = useState(preDiff)[1];

useEffect(() => {
let immediate = true;
return cache.watch({
...diffOptions,
immediate,
callback(newDiff) {
if (!immediate || !equal(newDiff, preDiff)) {
setDiff(newDiff);
}
immediate = false;
},
});
}, [preDiff]);

return {
data: preDiff.result,
complete: !!preDiff.complete,
missing: preDiff.missing,
};
}

0 comments on commit 7c21f05

Please sign in to comment.