relay: optimisticUpdater does not work

So, I have this code.

// @flow
import { graphql, commitMutation } from 'react-relay';
import type { Commit } from '../components/Mutation';
import type {
  DeleteWebMutationVariables,
  DeleteWebMutationResponse,
} from './__generated__/DeleteWebMutation.graphql';
import { ConnectionHandler } from 'relay-runtime';
import ensureConnection from './ensureConnection';

const mutation = graphql`
  mutation DeleteWebMutation($input: DeleteWebInput!) {
    deleteWeb(input: $input) {
      id
    }
  }
`;

const sharedUpdater = (store, id) => {
  const clientRoot = store.get('client:root');
  const connection = ConnectionHandler.getConnection(clientRoot, 'Webs_webs');
  ensureConnection(connection);
  ConnectionHandler.deleteNode(connection, id);
};

const commit: Commit<DeleteWebMutationVariables, DeleteWebMutationResponse> = (
  environment,
  variables,
  onCompleted,
  onError,
) =>
  commitMutation(environment, {
    mutation,
    variables,
    onCompleted,
    onError,
    updater: store => {
      const payload = store.getRootField('deleteWeb');
      const id = payload.getValue('id');
      sharedUpdater(store, id);
    },
    // This breaks everything.
    optimisticUpdater: store => {
      sharedUpdater(store, variables.input.id);
    },
  });

export default { commit };

As optimisticUpdater does not work. I don’t know why. Probably because of clientMutationId, maybe.

About this issue

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

Most upvoted comments

I have a similar issue than @steida

OptimisticUpdater remove the fifth node correctly but when relay does the rollback to continue with the normal updater the edge is restored but not his content or perhaps the second call to deleteNode remove the content but not the edge, I don’ know.

Then, react call the render function with undefined data and it crashes: image

I disabled the call to optimisticUpdater for now and it works: image

The root cause is not what you are thinking. optimisticUpdater does work, but the parameter passed in was incorrect. Whoever wrote that code did not realize an obvious limitation of relay by design.

The problem is status: "completed" in the connection args. Apparently there is no magic for relay to resolve a connection with filters dynamically at frontend, so relay just gives up updating that connection once it’s resolved.

That means, once the root query is resolved, this.props.viewer.completedTodos will never change. No matter how you change the state on the page, the optimistic updater is always trying to remove entries that are marked as completed when you initially open the page. Then the real updater kicks in later using the mutation on the server side to do the correct work, and overrides whatever optimistic updater has done incorrectly.

So there are two ways to fix this problem:

  1. Wrap a refetch container to keep completedTodos up to date. Obviously, this approach creates lots of network overhead… I’m going to skip how to implement this.
  2. Remove the filter status: "completed" from the fragment, then dynamically compute the completedTodos for RemoveCompletedTodosMutation. Please see the following:
 fragment TodoListFooter_viewer on User {
   id,
   completedCount,
-  completedTodos: todos(
-    status: "completed",
+  todos(
     first: 2147483647  # max GraphQLInt
-  ) {
+  ) @connection(key: "TodoList_todos") {
     edges {
       node {
         id
+      const edges = this.props.viewer.todos.edges.filter(edge => edge.node.complete === true)
       RemoveCompletedTodosMutation.commit(
         this.props.relay.environment,
-        this.props.viewer.completedTodos,
+        {
+          edges
+        },
         this.props.viewer
       )

Any update on this issue ? I have the same error than @SinHouse and I’m forced to disable the optimistic updater on node removal.

@alloy Unfortunately, no. Check https://github.com/este/este/blob/2a466085dfe2a85228580f02e73dfc8e08ed4c31/components/Webs.js#L33 I don’t have any filter there. It just doesn’t work in a way I described.

You can check out Este and try it for your self. Just uncomment this line https://github.com/este/este/blob/02ebb6399119d01108c1c031b0afa0d18c479b89/mutations/DeleteWebMutation.js#L45.

I think it must be a bug in Relay. cc @jstejada @kassens