Using `EditorView.scrollIntoView` in `transactionExtender` breaks `StateField` updates

If I return an EditorView.scrollIntoView effect from a transactionExtender, then my StateField’s start throwing errors when they update themselves!

My state field is an object containing a DecorationSet as a property. Something like this:

const myStateField = StateField.define({
  // intialise state field with a range that covers the entire editor
  create: (state) => ({
    set: Decoration.set([myMark.range(0, state.doc.length)])
  }),
  // update it as changes occur
  update: (val, tr) => {
    val.set = val.set.map(tr.changes);
    return val;
  },
});

Everything works when I return a new object from myStateField.update, but if I just update the existing one and return that, then it breaks. I suppose these StateField objects must always return a new instance of an object?

To make things very clear:

// this throws:
  update: (val, tr) => {
    val.set = val.set.map(tr.changes);
    return val;
  },

// this works:
  update: (val, tr) =>
    return { set: val.set.map(tr.changes) };
  },

I suppose CodeMirror is internally re-using the objects created by my StateField? Is this why it’s failing?

I’ve been able to make a small reproducible example here: Try CodeMirror

1 Like

Good! That is what you should be doing. Editor states, including any values attached to them, should be immutable.