question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Infinite loop caused by Type Policy with read function

See original GitHub issue

My app has a User type for which I’ve defined a type policy:

    User: {
      fields: {
        createdAt:  { read: (date) => date ? parseISO(date) : null },
      },
    },

I also have a query to fetch the currently logged in user, and a HOC is used to fetch that user and render sub components.

const GET_SELF = gql`
  query me {
    me {
      ...userFragment
      prefs { ...userPrefsFragment }
    }
  }
  
  ${Users.userFragment}
  ${Users.userPrefsFragment}
`;

const UserProvider = ({ render }) => {
  const { error, loading, data: { me } = {}, refetch, subscribeToMore } = useQuery(GET_SELF, { fetchPolicy: 'cache-first' });

  <snip>

  if (loading) return <Loading />;
  return render(me);
}

Now, in a subcomponent I’m running a query which fetches a set of users:

export const GET_MISSION = gql`
  query mission($id: ID!) {
    mission(_id: $id) {
      users { ...userDisplayFragment }
    }
  }

 ${userDisplayFragment}
`;

When that query returns the currently logged-in user as part of the users list, the code enters into an infinite loop.

The fields returned for the currently logged in user are merged into the user object in the cache. Despite the fact that these fields have not changed the value of that user object, this causes the ‘me’ query to rerun, which reruns the ‘mission’ query above, which leads to the infinite loop.

However, if I remove the createdAt field from the Type Policy for the User object then everything works.

I thought that I be able to work around the issue be returning the exact same parsed date object when the date doesn’t change:


class DatePolicy {
  constructor() {
    this.prevDate = null;
    this.prevParsedDate = null;
  }

  read = (date) => {
    if (date !== this.prevDate) {
      this.prevDate = date;
      this.prevParsedDate = date ? parseISO(date) : null;
    }

    return this.prevParsedDate;
  }
}

And using this class in the Type Policy:

User: {
  fields: {
    createdAt: new DatePolicy(),
  },
},

however that doesn’t solve the problem.

If however the read function returns the object unchanged then the loop is avoided:

read = (date) => date

So, it seems that when a read function that returns a value other than that passed in will force the query to re-run.

Versions

System: OS: macOS 10.15 Binaries: Node: 12.13.1 - ~/.nvm/versions/node/v12.13.1/bin/node Yarn: 1.19.2 - /usr/local/bin/yarn npm: 6.12.1 - ~/.nvm/versions/node/v12.13.1/bin/npm Browsers: Chrome: 85.0.4183.102 Firefox: 77.0.1 Safari: 13.0.2 npmPackages: @apollo/client: ^3.2.0 => 3.2.0 apollo-link-logger: ^1.2.3 => 1.2.3 apollo-server-express: ^2.17.0 => 2.17.0

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
ziggy6792commented, Apr 4, 2021

Hey @timothyarmes

Thanks for sharing this I was having the exact same issue. I came across this issue and @theodorDiaconu has done a brilliant job creating a small package that does what we want here. I followed his example and it works beautifully.

Good luck 😃

1reaction
brainkimcommented, Apr 9, 2021

Gentle reminder that we’re looking for reproductions. I greatly prioritize any issue which I can run, and I got a lot of issues on my plate at the moment. If not, I will get to this soon no worries 😇

Read more comments on GitHub >

github_iconTop Results From Across the Web

read() seems to go into infinite loop - Stack Overflow
I am trying to read data from a socket. For some reason I cannot understand, it seems the read function goes into an...
Read more >
How to solve the React useEffect Hook's infinite loop patterns
Solve the issue of infinite loops when using the useEffect Hook in React to more smoothly utilize the Hook for your app's side...
Read more >
Nested read statement leads to infinite loop in bash
Redirect the pipe to another file descriptor and loop around reading that so the inner read call is unaffected. Something like:
Read more >
5 useEffect Infinite Loop Patterns | by Naveen DA
useEffect hook triggers the callback function, only if the dependencies were changed. And it uses shallow comparison to compare the values of ...
Read more >
CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')
An infinite loop will cause unexpected consumption of resources, such as CPU cycles or memory. The software's operation may slow down, or cause...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found