RangeError: Applying a mismatched transaction

I’m a Prosemirror newbie that’s working to integrate the emoji mart React component with Prosemirror. I have it 95% of the way working, with the binding from PM to EM being implemented in a plugin/view. The problem I’m having (which Google has had precious little to say about) is when I intercept the “tab” key to insert the currently selected emoji. I’m doing this by binding the “tab” key to a method that dispatches a meta prop that the plugin interprets to know it should insert the suggested character.

To insert the currently suggested emoji, my view does this:

insertSelectedEmoji = (view, pluginState) => {
  const tr = view.state.tr;
  let emojiString = emojiSelectorString(pluginState.textStartPos, view.state) || "";
  tr.insertText(this.suggestedEmoji.native, pluginState.textStartPos, pluginState.textStartPos + emojiString.length + 1); // 1 covers the colon before the string
  view.dispatch(tr);
};

This code almost works - it successfully replaces my emoji string with the emoji that the popper had been suggesting. If you don’t press any more keys, the emoji is replaced and all looks well. The problem is that, the following keystroke, I get a “RangeError: Applying a mismatched transaction”

My best guess is that this is happening because the keymap dispatched a transaction, which was interpreted by the plugin, and subsequently the plugin’s view, which then dispatched its own transaction (shown above). I think that possibly the second dispatch is changing the state in a way that Prosemirror doesn’t expect?

Can anyone help me better understand/debug the “mismatched transaction” exception? And specifically, if it’s true that one can’t dispatch a new transform during a transaction dispatch, how am I supposed to react to a key event in a situation like this?

The code you show looks entirely valid, and it doesn’t look like it could be responsible for the error you’re getting.

“Mismatched transaction” errors mean that something is trying to dispatch a transaction that doesn’t start from the view’s current state—I.e. if you create the transaction but then don’t synchronously dispatch it, it’d be possible for another transaction to happen in the meantime, which makes your transaction invalid. The rest of the stack trace for the error likely points at the code that’s dispatching the transaction on the outdated (or, possibly, completely unrelated) state.

3 Likes

facing same problem,can you give the solutions for this my code

provider = new WebsocketProvider('ws: //localhost:8012', this.props.showRoom, ydoc, {})
type = ydoc.get(this.props.showRoom, Y.XmlFragment)
prosemirrorView = new EditorView(document.querySelector('#editor'),
{
  state: EditorState.create({
    schema,
    doc: Node.fromJSON(schema, this.props.scriptData),
    plugins: [
      ySyncPlugin(type),
      yCursorPlugin(provider.awareness),
      yUndoPlugin(),
      keymap({
        'Mod-z': undo,
        'Mod-y': redo,
        'Mod-Shift-z': redo
      })
    ].concat(exampleSetup({ schema
    }))
  }),
  dispatchTransaction: transaction => {
    const { state, transactions
    } = prosemirrorView.state.applyTransaction(transaction)
    prosemirrorView.updateState(state)
    if (transactions.some(tr => tr.docChanged)) {
      this.handleNewTextAppend(state.doc.toJSON())
    }
  },
})

i want to set initially databse content onload of prosemirror