When does useQuery hook cause a new render?

I’m confused about when useQuery’s conditions result in a new render.

Consider this working example: snowy-shadow-21zjv - CodeSandbox

I would expect the code below to work this way:

  1. Render a table with 1 todo
  2. If you click the status cell for a todo, the status is toggled.
  3. The cache for the list of todos is queried again, and now the one todo’s status has been flipped
  4. so the component renders and you see the status cell flip to the opposite emoji.
export default function Todos() {
  const { data, error, loading } = useQuery(Queries.GET_ALL_TODOS);
  const [toggleTodo] = useMutation(Mutations.TOGGLE_TODO, {
    refetchQueries: [{query: Queries.GET_ALL_TODOS}]
  });
  if (error) return error.message;
  if (loading) return "Loading...";

  return (
    <table>
      <thead>
        <tr>
          <td>Description</td>
          <td>Status</td>
        </tr>
      </thead>
      <tbody>
        {data.todos.map((todo) => {
          return (
            <tr key={todo.id}>
              <td>{todo.text}</td>
              <td
                onClick={() => {
                  toggleTodo({ variables: { id: todo.id.toString() } });
                }}
              >
                {!!todo.completed ? "✅" : "❌"}
              </td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

the way i have it working in the linked sandbox, i have to manually modify the cache in my mutation’s update() in order to get what react renders to reflect what the apollo dev tools show in the cache. by that i mean, if i look in the cache dev tools after running the toggle mutations, i can see that the todo i’m toggling has flipped its completed status as expected. but the refetch queries approach doesn’t work the way i’d expect.

i’m assuming that i’m abusing the API’s somehow, but i don’t know where to look.

Hello! I’m surprised that your refetchQueries solution was failing. I’ve forked your sandbox and believe it’s working here? userefetchqueries - CodeSandbox

Of particular note, I believe this example shouldn’t even require refetchQueries! Here’s another version of the sandbox that calls useMutation with no options, and the emoji updates correctly on click: usenothing - CodeSandbox

This works because your mutation returns the modified Todo object (importantly including its id, which is a great practice), meaning the Apollo Client cache knows which cached object to modify with the updated data.

Are these working for you as well?

2 Likes

Thanks for taking the time to test a few alternatives. You’re right, what I said wasn’t working - the refetchQueries strategy - actually is. I think maybe something weird was just happening with the interaction between the cache and hot-reloading on codesandbox. Thanks for the help!