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

Querying different fields on the same object in +layout and +page causes values to disappear in browser #1104

Closed
douglasward opened this issue Jun 6, 2023 · 8 comments
Labels
Still investigating Further information is requested

Comments

@douglasward
Copy link
Contributor

Describe the bug

It sounds similar to this issue #1020 but I am not using fragments, and even if i disable masking it doesn't seem to help.

If you run a query on an object in both +layout and +page then the values will be removed from the browser for the +page query.

Severity

serious, but I can work around it

Steps to Reproduce the Bug

query in +layout

query LayoutQuery {
  tenant {
    id
    featureFlags
  }
}

query in +page

query PageQuery {
  tenant {
    id
    name
  }
}

Both queries are run, but nothing is displayed in the in the page component:

<script lang="ts">
  export let data;
  $: ({ PageQuery } = data);
</script>

{$PageQuery?.data?.contact?.id}

Reproduction

No response

@jycouet
Copy link
Collaborator

jycouet commented Jun 6, 2023

Is it a typo the {$PageQuery?.data?.contact?.id}? Shouldn't it be something with tenant?
Could you check {$PageQuery?.data}?

@douglasward
Copy link
Contributor Author

ahh yes, I'm very sorry - I didn't catch that copy and paste mistake in my final minified test before leaving the office. So correcting that to tenant fixes showing the id in the template, but my actually use case was slightly different and involves custom load functions.

I am waiting for the data to be loading in the load function so I can initialize superforms with the data. My +page.ts looks like this:

import { load_PageQuery } from "$houdini";
import { formSchema } from "$lib/form-schemas/formSchema.schema";
import { waitForData } from "$lib/utils/graphql.util";
import { superValidate } from "sveltekit-superforms/server";

export const load = async (event) => {
  const { PageQuery } = await load_PageQuery({ event });

  const { tenant } = (await waitForData(PageQuery)) ?? {};

  const form = await superValidate(tenant, formSchema);

  return { form };
};

We had written a waitForData helper that was waiting for the query to resolve, like this:

import type { GraphQLObject, GraphQLVariables, QueryStore } from "$houdini";

export const waitForData = async <Data extends GraphQLObject, Input extends GraphQLVariables>(
  store: QueryStore<Data, Input>
) => {
  return await new Promise<Data | null>((resolve) => {
    store.subscribe(({ data }) => resolve(data));
  });
};

This had been working fine, but when adding the +layout queries of the same object, subscribing to the +page query would first return source cache and tenant null and then return source network and tenant with correct data. Since we were resolving the first time it returned something, we resolved with null. I have now updated the function to look like this:

export const waitForData = async <Data extends GraphQLObject, Input extends GraphQLVariables>(
  store: QueryStore<Data, Input>
) => {
  return await new Promise<Data | null>((resolve) => {
    store.subscribe(({ data, source, fetching }) => {
      console.log(data, source);
      if (
        !fetching &&
        ((source === "cache" && data && Object.keys(data).every((key) => data[key])) ||
          source === "network")
      ) {
        resolve(data);
      }
    });
  });
};

Which has "fixed" my use-case, but feels quite hacky. Is there a better way to wait for data in load functions to ease working with superforms?

@jycouet
Copy link
Collaborator

jycouet commented Jun 6, 2023

You could check out the blocking param.

const { PageQuery } = await load_PageQuery({ event, blocking: true });

@douglasward
Copy link
Contributor Author

That doesn't seem to have any effect.

@douglasward
Copy link
Contributor Author

ahh but I have defaultPartial enabled, maybe I should try disabling that to see if it has any effect

@jycouet
Copy link
Collaborator

jycouet commented Jun 8, 2023

That doesn't seem to have any effect.

A "real await" should happen with blocking: true, and you should have something in result

const result = await load_PageQuery({ event, blocking: true });

@AlecAivazis AlecAivazis added the Still investigating Further information is requested label Jun 8, 2023
@douglasward
Copy link
Contributor Author

Yes, that's what I had. I just tried with disabling deafultPartial and that did the trick.

Here with partial + blocking set to true:

{contact: {…}} 'network' 'CustomerLayout'
{contact: null} 'cache' 'CustomerPrivacy'
{contact: {…}} 'cache' 'CustomerPrivacy'
{contact: {…}} 'network' 'CustomerPrivacy'

And here with partial set to false and blocking set to true:

{contact: {…}} 'network' 'CustomerLayout'
{contact: {…}} 'network' 'CustomerPrivacy'

@douglasward
Copy link
Contributor Author

So I guess the issue is "solved" here, but maybe it is worth updating the docs regarding the usage of defaultPartial and blocking together so that confusion can be avoided in the future?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Still investigating Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants