relay: optimisticUpdater infinite loop

In the code below, the optimisticUpdater ends up in an infinite loop. It only occurs when I set a nested record on a newly created record, and set the linked record on a parent. eg.

1. const newNode = store.create(id, type)
2. newNode.getOrCreateLinkedRecord(key)
3. parent.setLinkedRecords([...oldNodes, newNode])

Why does it end up in a loop? How can I prevent it?

Resolves values and sets them on given record

function setValues(node, input) {
  Object.keys(input).forEach(key => {
    const value = input[key];
    if (Array.isArray(value)) node.setLinkedRecords(value, key);
    else if (isPlainObject(value)) {
      Object.keys(value).forEach(nestedKey => {
        const nestedNode = node.getOrCreateLinkedRecord(key);
        setValues(nestedNode, { [nestedKey]: value[nestedKey] });
      });
    } else node.setValue(value, key);
  });
}

Create handler

handleCreate = () => {
    const recordUpdater = ({ store, node }) => {
      const parent = store.get(this.props.customer.id);
      const nodes = (parent.getLinkedRecords("customerAddresses") || []).concat(node);

      parent.setLinkedRecords(nodes, "customerAddresses");
    };


    const config = {
      optimisticUpdater: store => {
        const id = `client:newCustomerAddress:${tempId++}`;
        const node = store.create(id, "CustomerAddress");

        node.setValue(id, "id");
        setValues(node, input);

        recordUpdater({ store, node });
      }
    };

    const input = {
      addressType: "Private",
      customerId: this.props.customer.id,
      address: {
        roadName: ""
      }
    };

      commitMutation(this.props.environment, {
        ...config,
        mutation,
        variables: { input },
        onCompleted: (resp, errors) => {
          if (errors) reject(errors);
          else resolve(resp);
        },
        reject
      })
  };

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 18 (10 by maintainers)

Most upvoted comments

As @sibelius noted, setValues()is the problem. setLinkedRecords accepts array of record proxies, and setLinkedRecord accepts a single record proxy. It’s possible to write something like your setValues() function that works, but it would have to distinguish the types of objects (e.g array of scalars vs array of objects) and convert all nested objects into record proxies with e.g. store.create or similar.