Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useFragment #1510

Open
kevinvalk opened this issue Sep 21, 2023 · 2 comments
Open

useFragment #1510

kevinvalk opened this issue Sep 21, 2023 · 2 comments

Comments

@kevinvalk
Copy link

Is your feature request related to a problem? Please describe.
I wanted to get a specific object from the cache that I knew would exist (because another query loading all objects of that type). Somehow graphQL (or useQuery) was not smart enough to resolve this object from cache via a normal useQuery. So I started reading the Apollo documentation and the useFragment hook they have https://www.apollographql.com/docs/react/api/react/hooks#usefragment sounded perfect! As in, just give me the data we have for a specific object.

Describe the solution you'd like
"Native" reactive useFragment method.

Describe alternatives you've considered
I ended up implementing a quick useFragment that gets the job done, but not more than that.

/**
 * Returns an always-up-to-date view of whatever data the cache currently contains for a given fragment and useFragment
 * never triggers network requests of its own.
 *
 * Based on https://www.apollographql.com/docs/react/api/react/hooks#usefragment code at https://github.com/apollographql/apollo-client/blob/a8fe0a1217d9784d3165e0ec2e88a2caca0f82d7/src/react/hooks/useFragment.ts#L1-L108
 * @param fragment
 * @param from
 * @param fragmentName
 */
export function useFragment<TResult = unknown, TVariables = unknown>(
  fragment: TypedDocumentNode<TResult, TVariables>,
  from: MaybeRefOrGetter<StoreObject | Reference | string | null | undefined>,
  fragmentName?: string
) {
  const { client } = useApolloClient();

  const data = shallowRef<TResult | undefined>(undefined);

  let unsubscribe: (() => void) | undefined = undefined;
  watchEffect(() => {
    const unwrappedFrom = toValue(from);

    // Remove our previous subscription
    if (unsubscribe !== undefined) {
      unsubscribe();
    }

    // If we have a from that is not "empty" we good!
    if (unwrappedFrom !== undefined && unwrappedFrom !== null) {
      unsubscribe = client.cache.watch<TResult, TVariables>({
        returnPartialData: true,
        immediate: true,
        id: typeof unwrappedFrom === 'string' ? unwrappedFrom : client.cache.identify(unwrappedFrom),
        // eslint-disable-next-line @typescript-eslint/dot-notation
        query: client.cache['getFragmentDoc'](fragment, fragmentName), // This is private, lol!
        optimistic: false,
        callback(diff) {
          // TODO: There is more to this I think: https://github.com/apollographql/apollo-client/blob/a8fe0a1217d9784d3165e0ec2e88a2caca0f82d7/src/react/hooks/useFragment.ts#L77-L82
          data.value = diff.result;
        },
      });
    }
  });

  return { data };
}

Additional context

@websitevirtuoso
Copy link
Contributor

Does this feature exist in @apollo/client ?

@kevinvalk
Copy link
Author

kevinvalk commented Oct 23, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants