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

Calling readFragment inside Type policies read function causes it update every time fragment changes #9306

Closed
valerii15298 opened this issue Jan 14, 2022 · 2 comments

Comments

@valerii15298
Copy link

Code sandbox link:
https://codesandbox.io/s/thirsty-paper-cx8f6?file=/src/App.js

I used the readFragment function inside type polices read function. Basically in my app, I need to use it to display data in a way I need. And a very interesting thing happened. When I update fragment using the updateFragment function, the read function executes too and data in UI is updated too.
And when I call the updateFragmentfunction with the same data but a different reference object it does not update and the read function does not execute.
So it is not clear if such behavior is considered to be always true or not?
I consider it as a bug because this behavior is not clearly described in the docs(at least by a few times reading it I did not find an explanation).

const typePolicies: TypedTypePolicies = {
  Query: {
    fields: {
      testField: {
        read(_, ctx) {
          const connId = ctx.args.id;
          const conn = ctx.cache.readFragment({
            id: `Connection:${connId}`,
            fragment: gql`
              fragment s on Connection {
                toPort {
                  id
                }
                fromPort {
                  id
                }
              }
            `,
          });
          console.log("testField resolver executed!");
          return { conn };
        },
      },
    },
  },
};

cache.writeFragment({
    id: `Connection:1`,
    fragment: gql`
      fragment test on Connection {
        id
        __typename
        toPort {
          id
        }
        fromPort {
          id
        }
      }
    `,
    data: {
      __typename: "Connection",
      id: 1,
      toPort: {
        id: 1,
      },
      fromPort: {
        id: 2,
      },
    },
  })

const TestApp = () => {
  const { error, loading, data } = useQuery(gql`
    query ExampleQuery {
      testField(id: 1)
    }
  `);

  if (error) return <div>Error: {error}</div>;
  if (loading) return <div>Loading...{loading}</div>;

  return (
    <div>
      <pre>{JSON.stringify(data, null, 2)}</pre>
      <button
        onClick={() => {
          cache.updateFragment(
            {
              id: `Connection:1`,
              fragment: gql`
                fragment conn on Connection {
                  toPort {
                    id
                  }
                  fromPort {
                    id
                  }
                }
              `,
            },
            (r) => {
              return {
                ...r,
                toPort: {
                  ...r.toPort,
                  id: Math.floor(Math.random() * 100),
                },
              };
            }
          );
        }}
      >
        Update connection
      </button>
    </div>
  );
};
@benjamn
Copy link
Member

benjamn commented Jan 18, 2022

@valerii15298 This reactivity is happening by design! That said, please let us know if it seems to be misbehaving in a way that couldn't possibly be correct.

If you really don't want your query to update when the fragment changes, you can run cache.readFragment outside the usual dependency context:

// At the top level of the module.
import { noContext } from "optimism";

// And then later, in your read function:
const conn = noContext(() => ctx.cache.readFragment(...));

Since no one has asked me this question before, I've never given that suggestion before, so I'd love to hear whether it works or not, if/when you have a chance to try it!

@valerii15298
Copy link
Author

Thanks for your response. Yep, it is working. I was curious and checked some of your repos including @wry/context from where this function is reexported and it is pretty interesting.
I am working on project where I replacing redux to apollo local state, trying to use It as one solution for state management. But there are a lot of logic especially with local-only data that is why i am trying understand apollo on a good level. Maybe I would suggest describe it in more detail explicitly in the documentation. It was not clear in docs for me that readFragment is also reactive in typePolicies(I thought only ctx.readField is reactive). But anyway my doubt was resolved, thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants