urql: Cannot update a component (`Component`) while rendering a different component (`OtherComponent`).

Getting this error in any component where I’m using useQuery. Using React and the following exchanges:

The stack trace points to this line:

https://github.com/FormidableLabs/urql/blob/47eaff17fcf72684eb12bd1009d3014f91a81c86/packages/react-urql/src/hooks/useQuery.ts#L149

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 18 (8 by maintainers)

Most upvoted comments

I am seeing this issue even with one hook (e.g. when switching between pages):

Warning: Cannot update a component (`Navbar`) while rendering a different component (`Navbar`).

with

export default function Navbar(): ReactElement {
   const [plan] = usePlanQuery()
}

I suspect this issue is due to missing garbage collection when the component gets out of scope. I managed to find a workaround as follows:

export default function Navbar(): ReactElement {
   const ref = useRef()

   const [plan] = usePlanQuery({ pause: !ref.current })

   return <div ref={ref} />
}

@kitten Hello. I wasn’t able to find the cause of the error back then. I’m commenting here because I’m getting it again, this time I can pinpoint a specific code modification that leads to it.

When I have two queries like this :

const [resultA] = useQuery({ query: QueryADocument });
const [resultB] = useQuery({ query: QueryBDocument });

I don’t get the error. However, pausing the second to wait for the first triggers the error :

const [resultA] = useQuery({ query: QueryADocument });
const [resultB] = useQuery({ query: QueryBDocument, pause: !resultA.data });

Btw I’m sorry I’m in a rush, I don’t have time to setup a proper reproduction. I might do it in the futur if I don’t find another cause for this error.

Just two comments:

@danbeneventano Don’t think this is related to network as the issue occurs in my local development environment. @kitten: This is “just a warning”, so it can be overlooked easily.

Unfortunately the issue occurs in a larger code base that I cannot share, so I cannot promise a reproduction. The general pattern in my case:

  • 2 identical(!) useQuery
  • the second useQuery is in a child of the first useQuery but many levels down the React tree
  • problem is triggered, when I call the query re-execution function of the hook
  • it does not matter, if I call the re-execution function in the parent or the child, problem is present in both cases

I hope this description at least gives some hints on how this may be reproduced.

I’m still getting this error occasionally, even with not a single duplicated query, and I have not been able to figure out why. I agree that this is against the point of react hooks. For example, I should be able to use my useCurrentUser hook everywhere. Right now this error is forcing me to set up the query in a provider and use React Context for my useCurrentUser hook. This is a total PITA. I would expect to be able to use the same query hook in multiple components, and this has not been an issue with any other fetching library I have tried.

@JoviDeCroock @kitten Can this be reopened?

Hiya 👋

Just a quick note, we recognise this issue from a previous fix we had to do on a prior implementation of our React hooks bindings. That being said, usually we’d ask for more details that follow our bug template and possibly provide a reproduction: https://raw.githubusercontent.com/FormidableLabs/urql/main/.github/ISSUE_TEMPLATE/Bug_report.md

To give you more information on what’s going on here; because the hooks have the option to use React suspense and suspend on any changes, they perform checks during render to determine whether their state is out-of-date and whether they need to request a change. When that change happens they briefly poll the client for a synchronous check on whether the new state is already ready without fetching against the API. When this result comes back all useQuery hooks with the same input see this result and will trigger an update. This is something that the React team has put an explicit warning into the reconciler for.

That being said, this will only happen when:

  • useQuery is mounted (or updated) with a query and set of variables
  • A second useQuery hook is mounted (or updated) elsewhere with the same query and same set of variables

Hence, I do have to warn you, while we will mute this warning in a patch with the PR that’s linked, this is a slight problem in GraphQL apps, since it shouldn’t be necessary to create multiple query hooks with the same inputs and its more advisable to hoist as many data requirements as possible to the top of a page and to let the rest of the components reuse this same data (passing and splitting it via props)

So that’s just a side note on the issue in general ✌️

I’m seeing this in 2.0.5. It seems like two different components are fetching the same query, but with different fields. As a result, one is updating the other. A bit hard to reproduce, since it feels like a race condition, but I’ll try if no one else has reproduced.

Interestingly, I’m seeing this error in the browser, but not in React Native. Maybe native is just silencing it? Not sure.

Update

I managed to get around it with a hack similar to @strblr’s comment.

const [artist] = useArtist()

const [artistPricing] = useArtistPricing({
  pause: !artist.data
})

This isn’t ideal, since I would like them to fetch in tandem.

@kitten: Okay, I will try to make a reproduction and open a new issue if I succeed.

@kitten: Could you please re-open this issue (or shall we make a new one?). The issue is hard to debug and makes using urql hooks a nightmare in larger code-bases.

@kitten Same error here as @danbeneventano, without any duplicate query. I simply have something like this :

export default function List({ project, principles, renderItem }: Props) {
  const [filters] = useListVariables({});
  const [{ data, fetching }] = useEngineeringArticlesQuery({ // generated by codegen
    variables: {
      ...filters,
      principles,
      projectId: project?.id
    }
  });
  return (
    <ListView
      loading={fetching}
      content={data?.engineeringArticles}
      renderItem={renderItem ?? (article => <Item.Admin article={article} />)}
    />
  );
}

When props change, thus variables changes :

index.js:1 Warning: Cannot update a component (`Page`) while rendering a different component (`List`). To locate the bad setState() call inside `List`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
    at List
    at div
    at div
    at Card
    ......

@danbeneventano I’m sorry you’re still having trouble with this. Curiously we do have several apps that also use shared hook state extensively. Can you point to a reproduction with the latest version of urql and React? If not, we’ll have to see whether it occurs in the apps we have, but I haven’t seen this for several versions

I’ll see if I can produce a reproduction, but it’s been happening very unpredictably (maybe related to network speed)